Version 0.6.14.0 .
svn merge -r 25579:25717 https://dart.googlecode.com/svn/branches/bleeding_edge trunk
git-svn-id: http://dart.googlecode.com/svn/trunk@25719 260f80e4-7a28-3924-810f-c04153c831b5
diff --git a/dart.gyp b/dart.gyp
index 0b02fc1..70d9da6 100644
--- a/dart.gyp
+++ b/dart.gyp
@@ -44,6 +44,7 @@
['OS!="android"', {
'dependencies': [
'runtime/dart-runtime.gyp:test_extension',
+ 'samples/sample_extension/sample_extension.gyp:sample_extension',
],
}],
],
diff --git a/pkg/analyzer_experimental/lib/analyzer.dart b/pkg/analyzer_experimental/lib/analyzer.dart
index 2a9d9ac..644009c 100644
--- a/pkg/analyzer_experimental/lib/analyzer.dart
+++ b/pkg/analyzer_experimental/lib/analyzer.dart
@@ -26,7 +26,16 @@
var contents = new File(path).readAsStringSync();
var errorCollector = new _ErrorCollector();
var sourceFactory = new SourceFactory.con2([new FileUriResolver()]);
- var source = sourceFactory.forUri(pathos.toUri(path).toString());
+
+ var absolutePath = pathos.absolute(path);
+ var source = sourceFactory.forUri(pathos.toUri(absolutePath).toString());
+ if (source == null) {
+ throw new ArgumentError("Can't get source for path $path");
+ }
+ if (!source.exists()) {
+ throw new ArgumentError("Source $source doesn't exist");
+ }
+
var scanner = new StringScanner(source, contents, errorCollector);
var token = scanner.tokenize();
var parser = new Parser(source, errorCollector);
diff --git a/pkg/barback/lib/barback.dart b/pkg/barback/lib/barback.dart
index eb0e1e8..539d732 100644
--- a/pkg/barback/lib/barback.dart
+++ b/pkg/barback/lib/barback.dart
@@ -6,6 +6,7 @@
export 'src/asset.dart';
export 'src/asset_id.dart';
+export 'src/barback.dart';
export 'src/errors.dart';
export 'src/package_provider.dart';
export 'src/transform.dart' show Transform;
diff --git a/pkg/barback/lib/src/asset_cascade.dart b/pkg/barback/lib/src/asset_cascade.dart
index 3d6416f..40a615c 100644
--- a/pkg/barback/lib/src/asset_cascade.dart
+++ b/pkg/barback/lib/src/asset_cascade.dart
@@ -7,9 +7,12 @@
import 'dart:async';
import 'dart:collection';
+import 'package:stack_trace/stack_trace.dart';
+
import 'asset.dart';
import 'asset_id.dart';
-import 'asset_set.dart';
+import 'asset_node.dart';
+import 'cancelable_future.dart';
import 'errors.dart';
import 'change_batch.dart';
import 'package_graph.dart';
@@ -36,6 +39,17 @@
/// the current app.
final PackageGraph _graph;
+ /// The controllers for the [AssetNode]s that provide information about this
+ /// cascade's package's source assets.
+ final _sourceControllerMap = new Map<AssetId, AssetNodeController>();
+
+ /// Futures for source assets that are currently being loaded.
+ ///
+ /// These futures are cancelable so that if an asset is updated after a load
+ /// has been kicked off, the previous load can be ignored in favor of a new
+ /// one.
+ final _loadingSources = new Map<AssetId, CancelableFuture<Asset>>();
+
final _phases = <Phase>[];
/// A stream that emits a [BuildResult] each time the build is completed,
@@ -66,7 +80,9 @@
/// If no build it in progress, is `null`.
Future _processDone;
- ChangeBatch _sourceChanges;
+ /// Whether any source assets have been updated or removed since processing
+ /// last began.
+ var _newChanges = false;
/// Creates a new [AssetCascade].
///
@@ -104,54 +120,95 @@
// * [id] may be generated before the compilation is finished. We should
// be able to quickly check whether there are any more in-place
// transformations that can be run on it. If not, we can return it early.
- // * If everything is compiled, something that didn't output [id] is
- // dirtied, and then [id] is requested, we can return it immediately,
- // since anything overwriting it at that point is an error.
// * If [id] has never been generated and all active transformers provide
// metadata about the file names of assets it can emit, we can prove that
// none of them can emit [id] and fail early.
- return (_processDone == null ? new Future.value() : _processDone).then((_) {
- // Each phase's inputs are the outputs of the previous phase. Find the
- // last phase that contains the asset. Since the last phase has no
- // transformers, this will find the latest output for that id.
+ return newFuture(() {
+ var node = _getAssetNode(id);
- // TODO(rnystrom): Currently does not omit assets that are actually used
- // as inputs for transformers. This means you can request and get an
- // asset that should be "consumed" because it's used to generate the
- // real asset you care about. Need to figure out how we want to handle
- // that and what use cases there are related to it.
- for (var i = _phases.length - 1; i >= 0; i--) {
- var node = _phases[i].inputs[id];
- if (node != null) {
- // By the time we get here, the asset should have been built.
- assert(node.asset != null);
- return node.asset;
- }
+ // If the requested asset is available, we can just return it.
+ if (node != null) return node.asset;
+
+ // If there's a build running, that build might generate the asset, so we
+ // wait for it to complete and then try again.
+ if (_processDone != null) {
+ return _processDone.then((_) => getAssetById(id));
}
- // Couldn't find it.
+ // If the asset hasn't been built and nothing is building now, the asset
+ // won't be generated, so we throw an error.
throw new AssetNotFoundException(id);
});
}
+ // Returns the post-transformation asset node for [id], if one is available.
+ //
+ // This will only return a node that has an asset available, and only if that
+ // node is guaranteed not to be consumed by any transforms. If the phase is
+ // still working to figure out if a node will be consumed by a transformer,
+ // that node won't be returned.
+ AssetNode _getAssetNode(AssetId id) {
+ // Each phase's inputs are the outputs of the previous phase. Find the last
+ // phase that contains the asset. Since the last phase has no transformers,
+ // this will find the latest output for that id.
+ for (var i = _phases.length - 1; i >= 0; i--) {
+ var node = _phases[i].getUnconsumedInput(id);
+ if (node != null) return node;
+ }
+
+ return null;
+ }
+
/// Adds [sources] to the graph's known set of source assets.
///
/// Begins applying any transforms that can consume any of the sources. If a
/// given source is already known, it is considered modified and all
/// transforms that use it will be re-applied.
void updateSources(Iterable<AssetId> sources) {
- if (_sourceChanges == null) _sourceChanges = new ChangeBatch();
- assert(sources.every((id) => id.package == package));
- _sourceChanges.update(sources);
+ _newChanges = true;
+
+ for (var id in sources) {
+ var controller = _sourceControllerMap[id];
+ if (controller != null) {
+ controller.setDirty();
+ } else {
+ _sourceControllerMap[id] = new AssetNodeController(id);
+ _phases.first.addInput(_sourceControllerMap[id].node);
+ }
+
+ // If this source was already loading, cancel the old load, since it may
+ // return out-of-date contents for the asset.
+ if (_loadingSources.containsKey(id)) _loadingSources[id].cancel();
+
+ _loadingSources[id] =
+ new CancelableFuture<Asset>(_graph.provider.getAsset(id));
+ _loadingSources[id].whenComplete(() {
+ _loadingSources.remove(id);
+ }).then((asset) {
+ var controller = _sourceControllerMap[id].setAvailable(asset);
+ }).catchError((error) {
+ reportError(error);
+
+ // TODO(nweiz): propagate error information through asset nodes.
+ _sourceControllerMap.remove(id).setRemoved();
+ });
+ }
_waitForProcess();
}
/// Removes [removed] from the graph's known set of source assets.
void removeSources(Iterable<AssetId> removed) {
- if (_sourceChanges == null) _sourceChanges = new ChangeBatch();
- assert(removed.every((id) => id.package == package));
- _sourceChanges.remove(removed);
+ _newChanges = true;
+
+ removed.forEach((id) {
+ // If the source was being loaded, cancel that load.
+ if (_loadingSources.containsKey(id)) _loadingSources.remove(id).cancel();
+
+ var controller = _sourceControllerMap.remove(id);
+ // Don't choke if an id is double-removed for some reason.
+ if (controller != null) controller.setRemoved();
+ });
_waitForProcess();
}
@@ -196,7 +253,8 @@
///
/// Returns a future that completes when all assets have been processed.
Future _process() {
- return _processSourceChanges().then((_) {
+ _newChanges = false;
+ return newFuture(() {
// Find the first phase that has work to do and do it.
var future;
for (var phase in _phases) {
@@ -207,7 +265,7 @@
// If all phases are done and no new updates have come in, we're done.
if (future == null) {
// If changes have come in, start over.
- if (_sourceChanges != null) return _process();
+ if (_newChanges) return _process();
// Otherwise, everything is done.
return;
@@ -217,42 +275,6 @@
return future.then((_) => _process());
});
}
-
- /// Processes the current batch of changes to source assets.
- Future _processSourceChanges() {
- // Always pump the event loop. This ensures a bunch of synchronous source
- // changes are processed in a single batch even when the first one starts
- // the build process.
- return newFuture(() {
- if (_sourceChanges == null) return null;
-
- // Take the current batch to ensure it doesn't get added to while we're
- // processing it.
- var changes = _sourceChanges;
- _sourceChanges = null;
-
- var updated = new AssetSet();
- var futures = [];
- for (var id in changes.updated) {
- // TODO(rnystrom): Catch all errors from provider and route to results.
- futures.add(_graph.provider.getAsset(id).then((asset) {
- updated.add(asset);
- }).catchError((error) {
- if (error is AssetNotFoundException) {
- // Handle missing asset errors like regular missing assets.
- reportError(error);
- } else {
- // It's an unexpected error, so rethrow it.
- throw error;
- }
- }));
- }
-
- return Future.wait(futures).then((_) {
- _phases.first.updateInputs(updated, changes.removed);
- });
- });
- }
}
/// An event indicating that the cascade has finished building all assets.
diff --git a/pkg/barback/lib/src/asset_node.dart b/pkg/barback/lib/src/asset_node.dart
index ae2b70e..6e7789a 100644
--- a/pkg/barback/lib/src/asset_node.dart
+++ b/pkg/barback/lib/src/asset_node.dart
@@ -8,30 +8,189 @@
import 'asset.dart';
import 'asset_id.dart';
+import 'errors.dart';
import 'phase.dart';
import 'transform_node.dart';
-/// Describes an asset and its relationship to the build dependency graph.
+/// Describes the current state of an asset as part of a transformation graph.
///
-/// Keeps a cache of the last asset that was built for this node (i.e. for this
-/// node's ID and phase) and tracks which transforms depend on it.
+/// An asset node can be in one of three states (see [AssetState]). It provides
+/// an [onStateChange] stream that emits an event whenever it changes state.
+///
+/// Asset nodes are controlled using [AssetNodeController]s.
class AssetNode {
- Asset asset;
+ /// The id of the asset that this node represents.
+ final AssetId id;
- /// The [TransformNode]s that consume this node's asset as an input.
- final consumers = new Set<TransformNode>();
+ /// The current state of the asset node.
+ AssetState get state => _state;
+ AssetState _state;
- AssetId get id => asset.id;
+ /// The concrete asset that this node represents.
+ ///
+ /// This is null unless [state] is [AssetState.AVAILABLE].
+ Asset get asset => _asset;
+ Asset _asset;
- AssetNode(this.asset);
+ /// A broadcast stream that emits an event whenever the node changes state.
+ ///
+ /// This stream is synchronous to ensure that when a source asset is modified
+ /// or removed, the appropriate portion of the asset graph is dirtied before
+ /// any [Barback.getAssetById] calls emit newly-incorrect values.
+ Stream<AssetState> get onStateChange => _stateChangeController.stream;
- /// Updates this node's generated asset value and marks all transforms that
- /// use this as dirty.
- void updateAsset(Asset asset) {
- // Cannot update an asset to one with a different ID.
- assert(id == asset.id);
+ /// This is synchronous so that a source being updated will always be
+ /// propagated through the build graph before anything that depends on it is
+ /// requested.
+ final _stateChangeController =
+ new StreamController<AssetState>.broadcast(sync: true);
- this.asset = asset;
- consumers.forEach((consumer) => consumer.dirty());
+ /// Returns a Future that completes when the node's asset is available.
+ ///
+ /// If the asset is currently available, this completes synchronously to
+ /// ensure that the asset is still available in the [Future.then] callback.
+ ///
+ /// If the asset is removed before becoming available, this will throw an
+ /// [AssetNotFoundException].
+ Future<Asset> get whenAvailable {
+ return _waitForState((state) => state.isAvailable || state.isRemoved)
+ .then((state) {
+ if (state.isRemoved) throw new AssetNotFoundException(id);
+ return asset;
+ });
}
+
+ /// Returns a Future that completes when the node's asset is removed.
+ ///
+ /// If the asset is already removed when this is called, it completes
+ /// synchronously.
+ Future get whenRemoved => _waitForState((state) => state.isRemoved);
+
+ /// Runs [callback] repeatedly until the node's asset has maintained the same
+ /// value for the duration.
+ ///
+ /// This will run [callback] as soon as the asset is available (synchronously
+ /// if it's available immediately). If the [state] changes at all while
+ /// waiting for the Future returned by [callback] to complete, it will be
+ /// re-run as soon as it completes and the asset is available again. This will
+ /// continue until [state] doesn't change at all.
+ ///
+ /// If this asset is removed, this will throw an [AssetNotFoundException] as
+ /// soon as [callback]'s Future is finished running.
+ Future tryUntilStable(Future callback(Asset asset)) {
+ return whenAvailable.then((asset) {
+ var modifiedDuringCallback = false;
+ var subscription;
+ subscription = onStateChange.listen((_) {
+ modifiedDuringCallback = true;
+ subscription.cancel();
+ });
+
+ return callback(asset).then((result) {
+ subscription.cancel();
+
+ // If the asset was modified at all while running the callback, the
+ // result was invalid and we should try again.
+ if (modifiedDuringCallback) return tryUntilStable(callback);
+ return result;
+ });
+ });
+ }
+
+ /// Returns a Future that completes as soon as the node is in a state that
+ /// matches [test].
+ ///
+ /// The Future completes synchronously if this is already in such a state.
+ Future<AssetState> _waitForState(bool test(AssetState state)) {
+ if (test(state)) return new Future.sync(() => state);
+ return onStateChange.firstWhere(test);
+ }
+
+ AssetNode._(this.id)
+ : _state = AssetState.DIRTY;
+
+ AssetNode._available(Asset asset)
+ : id = asset.id,
+ _asset = asset,
+ _state = AssetState.AVAILABLE;
+}
+
+/// The controller for an [AssetNode].
+///
+/// This controls which state the node is in.
+class AssetNodeController {
+ final AssetNode node;
+
+ /// Creates a controller for a dirty node.
+ AssetNodeController(AssetId id)
+ : node = new AssetNode._(id);
+
+ /// Creates a controller for an available node with the given concrete
+ /// [asset].
+ AssetNodeController.available(Asset asset)
+ : node = new AssetNode._available(asset);
+
+ /// Marks the node as [AssetState.DIRTY].
+ void setDirty() {
+ assert(node._state != AssetState.REMOVED);
+ node._state = AssetState.DIRTY;
+ node._asset = null;
+ node._stateChangeController.add(AssetState.DIRTY);
+ }
+
+ /// Marks the node as [AssetState.REMOVED].
+ ///
+ /// Once a node is marked as removed, it can't be marked as any other state.
+ /// If a new asset is created with the same id, it will get a new node.
+ void setRemoved() {
+ assert(node._state != AssetState.REMOVED);
+ node._state = AssetState.REMOVED;
+ node._asset = null;
+ node._stateChangeController.add(AssetState.REMOVED);
+ }
+
+ /// Marks the node as [AssetState.AVAILABLE] with the given concrete [asset].
+ ///
+ /// It's an error to mark an already-available node as available. It should be
+ /// marked as dirty first.
+ void setAvailable(Asset asset) {
+ assert(asset.id == node.id);
+ assert(node._state != AssetState.REMOVED);
+ assert(node._state != AssetState.AVAILABLE);
+ node._state = AssetState.AVAILABLE;
+ node._asset = asset;
+ node._stateChangeController.add(AssetState.AVAILABLE);
+ }
+}
+
+// TODO(nweiz): add an error state.
+/// An enum of states that an [AssetNode] can be in.
+class AssetState {
+ /// The node has a concrete asset loaded, available, and up-to-date. The asset
+ /// is accessible via [AssetNode.asset]. An asset can only be marked available
+ /// again from the [AssetState.DIRTY] state.
+ static final AVAILABLE = const AssetState._("available");
+
+ /// The asset is no longer available, possibly for good. A removed asset will
+ /// never enter another state.
+ static final REMOVED = const AssetState._("removed");
+
+ /// The asset will exist in the future (unless it's removed), but the concrete
+ /// asset is not yet available.
+ static final DIRTY = const AssetState._("dirty");
+
+ /// Whether this state is [AssetState.AVAILABLE].
+ bool get isAvailable => this == AssetState.AVAILABLE;
+
+ /// Whether this state is [AssetState.REMOVED].
+ bool get isRemoved => this == AssetState.REMOVED;
+
+ /// Whether this state is [AssetState.DIRTY].
+ bool get isDirty => this == AssetState.DIRTY;
+
+ final String name;
+
+ const AssetState._(this.name);
+
+ String toString() => name;
}
diff --git a/pkg/barback/lib/src/asset_set.dart b/pkg/barback/lib/src/asset_set.dart
index f58e188..b432425 100644
--- a/pkg/barback/lib/src/asset_set.dart
+++ b/pkg/barback/lib/src/asset_set.dart
@@ -18,6 +18,18 @@
class AssetSet extends IterableBase<Asset> {
final _assets = new Map<AssetId, Asset>();
+ AssetSet();
+
+ /// Creates a new AssetSet from the contents of [other].
+ ///
+ /// If multiple assets in [other] have the same id, the last one takes
+ /// precedence.
+ AssetSet.from(Iterable<Asset> other) {
+ for (var asset in other) {
+ _assets[asset.id] = asset;
+ }
+ }
+
Iterator<Asset> get iterator => _assets.values.iterator;
int get length => _assets.length;
@@ -51,6 +63,9 @@
return _assets.containsKey(id);
}
+ /// If the set contains an [Asset] with [id], removes and returns it.
+ Asset removeId(AssetId id) => _assets.remove(id);
+
/// Removes all assets from the set.
void clear() {
_assets.clear();
diff --git a/pkg/barback/lib/src/barback.dart b/pkg/barback/lib/src/barback.dart
new file mode 100644
index 0000000..2797c1a
--- /dev/null
+++ b/pkg/barback/lib/src/barback.dart
@@ -0,0 +1,85 @@
+// Copyright (c) 2013, 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 barback.barback;
+
+import 'dart:async';
+
+import 'asset.dart';
+import 'asset_id.dart';
+import 'asset_cascade.dart';
+import 'package_graph.dart';
+import 'package_provider.dart';
+
+/// A general-purpose asynchronous build dependency graph manager.
+///
+/// It consumes source assets (including Dart files) in a set of packages,
+/// runs transformations on them, and then tracks which sources have been
+/// modified and which transformations need to be re-run.
+///
+/// To do this, you give barback a [PackageProvider] which can yield a set of
+/// [Transformer]s and raw source [Asset]s. Then you tell it which input files
+/// have been added or modified by calling [updateSources]. Barback will
+/// automatically wire up the appropriate transformers to those inputs and
+/// start running them asynchronously. If a transformer produces outputs that
+/// can be consumed by other transformers, they will automatically be pipelined
+/// correctly.
+///
+/// You can then request assets (either source or generated) by calling
+/// [getAssetById]. This will wait for any necessary transformations and then
+/// return the asset.
+///
+/// When source files have been modified or removed, tell barback by calling
+/// [updateSources] and [removeSources] as appropriate. Barback will
+/// automatically track which transformations are affected by those changes and
+/// re-run them as needed.
+///
+/// Barback tries to be resilient to errors since assets are often in an
+/// in-progress state. When errors occur, they will be captured and emitted on
+/// the [errors] stream.
+class Barback {
+ /// The graph managed by this instance.
+ final PackageGraph _graph;
+
+ /// A stream that emits a [BuildResult] each time the build is completed,
+ /// whether or not it succeeded.
+ ///
+ /// This will emit a result only once every package's [AssetCascade] has
+ /// finished building.
+ ///
+ /// If an unexpected error in barback itself occurs, it will be emitted
+ /// through this stream's error channel.
+ Stream<BuildResult> get results => _graph.results;
+
+ /// A stream that emits any errors from the graph or the transformers.
+ ///
+ /// This emits errors as they're detected. If an error occurs in one part of
+ /// the graph, unrelated parts will continue building.
+ ///
+ /// This will not emit programming errors from barback itself. Those will be
+ /// emitted through the [results] stream's error channel.
+ Stream get errors => _graph.errors;
+
+ Barback(PackageProvider provider)
+ : _graph = new PackageGraph(provider);
+
+ /// Gets the asset identified by [id].
+ ///
+ /// If [id] is for a generated or transformed asset, this will wait until
+ /// it has been created and return it. If the asset cannot be found, throws
+ /// [AssetNotFoundException].
+ Future<Asset> getAssetById(AssetId id) => _graph.getAssetById(id);
+
+ /// Adds [sources] to the graph's known set of source assets.
+ ///
+ /// Begins applying any transforms that can consume any of the sources. If a
+ /// given source is already known, it is considered modified and all
+ /// transforms that use it will be re-applied.
+ void updateSources(Iterable<AssetId> sources) =>
+ _graph.updateSources(sources);
+
+ /// Removes [removed] from the graph's known set of source assets.
+ void removeSources(Iterable<AssetId> removed) =>
+ _graph.removeSources(removed);
+}
\ No newline at end of file
diff --git a/pkg/barback/lib/src/cancelable_future.dart b/pkg/barback/lib/src/cancelable_future.dart
new file mode 100644
index 0000000..043ad6c
--- /dev/null
+++ b/pkg/barback/lib/src/cancelable_future.dart
@@ -0,0 +1,40 @@
+// Copyright (c) 2013, 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 barback.cancelable_future;
+
+import 'dart:async';
+
+/// A wrapper for [Future] that can be cancelled.
+///
+/// When this is cancelled, that means it won't complete either successfully or
+/// with an error, regardless of whether the wrapped Future completes.
+/// Cancelling this won't stop whatever code is feeding the wrapped future from
+/// running.
+class CancelableFuture<T> implements Future<T> {
+ bool _canceled = false;
+ final _completer = new Completer<T>();
+
+ CancelableFuture(Future<T> inner) {
+ inner.then((result) {
+ if (_canceled) return;
+ _completer.complete(result);
+ }).catchError((error) {
+ if (_canceled) return;
+ _completer.completeError(error);
+ });
+ }
+
+ Stream<T> asStream() => _completer.future.asStream();
+ Future catchError(onError(asyncError), {bool test(error)}) =>
+ _completer.future.catchError(onError, test: test);
+ Future then(onValue(T value), {onError(error)}) =>
+ _completer.future.then(onValue, onError: onError);
+ Future<T> whenComplete(action()) => _completer.future.whenComplete(action);
+
+ /// Cancels this future.
+ void cancel() {
+ _canceled = true;
+ }
+}
diff --git a/pkg/barback/lib/src/package_provider.dart b/pkg/barback/lib/src/package_provider.dart
index 8506d14..031caf8 100644
--- a/pkg/barback/lib/src/package_provider.dart
+++ b/pkg/barback/lib/src/package_provider.dart
@@ -21,19 +21,15 @@
/// dependencies.
Iterable<String> get packages;
- // TODO(rnystrom): Make this async.
- /// The paths of all available asset files in [package], relative to the
- /// package's root directory.
- ///
- /// You can pass [within], which should be the relative path to a directory
- /// within the package, to only return the files within that subdirectory.
- List<AssetId> listAssets(String package, {String within});
-
/// Returns the list of transformer phases that are applicable to [package].
///
/// The phases will be run in sequence, with the outputs of one pipelined into
/// the next. All [Transformer]s in a single phase will be run in parallel.
Iterable<Iterable<Transformer>> getTransformers(String package);
+ /// Loads an asset from disk.
+ ///
+ /// This should be re-entrant; it may be called multiple times with the same
+ /// id before the previously returned future has completed.
Future<Asset> getAsset(AssetId id);
}
diff --git a/pkg/barback/lib/src/phase.dart b/pkg/barback/lib/src/phase.dart
index e16f94b..4d2afb4 100644
--- a/pkg/barback/lib/src/phase.dart
+++ b/pkg/barback/lib/src/phase.dart
@@ -14,6 +14,7 @@
import 'errors.dart';
import 'transform_node.dart';
import 'transformer.dart';
+import 'utils.dart';
/// One phase in the ordered series of transformations in an [AssetCascade].
///
@@ -45,19 +46,32 @@
/// phases, they will be the outputs from the previous phase.
final inputs = new Map<AssetId, AssetNode>();
- /// The transforms currently applicable to assets in [inputs].
+ /// The transforms currently applicable to assets in [inputs], indexed by
+ /// the ids of their primary inputs.
///
/// These are the transforms that have been "wired up": they represent a
/// repeatable transformation of a single concrete set of inputs. "dart2js"
/// is a transformer. "dart2js on web/main.dart" is a transform.
- final _transforms = new Set<TransformNode>();
+ final _transforms = new Map<AssetId, Set<TransformNode>>();
- /// The nodes that are new in this phase since the last time [process] was
- /// called.
+ /// Futures that will complete once the transformers that can consume a given
+ /// asset are determined.
///
- /// When we process, we'll check these to see if we can hang new transforms
- /// off them.
- final _newInputs = new Set<AssetNode>();
+ /// Whenever an asset is added or modified, we need to asynchronously
+ /// determine which transformers can use it as their primary input. We can't
+ /// start processing until we know which transformers to run, and this allows
+ /// us to wait until we do.
+ var _adjustTransformersFutures = new Map<AssetId, Future>();
+
+ /// New asset nodes that were added while [_adjustTransformers] was still
+ /// being run on an old version of that asset.
+ var _pendingNewInputs = new Map<AssetId, AssetNode>();
+
+ /// The ids of assets that are emitted by transforms in this phase.
+ ///
+ /// This is used to detect collisions where multiple transforms emit the same
+ /// output.
+ final _outputs = new Set<AssetId>();
/// The phase after this one.
///
@@ -66,133 +80,217 @@
Phase(this.cascade, this._index, this._transformers, this._next);
- /// Updates the phase's inputs with [updated] and removes [removed].
+ /// Adds a new asset as an input for this phase.
///
- /// This marks any affected [transforms] as dirty or discards them if their
- /// inputs are removed.
- void updateInputs(AssetSet updated, Set<AssetId> removed) {
- // Remove any nodes that are no longer being output. Handle removals first
- // in case there are assets that were removed by one transform but updated
- // by another. In that case, the update should win.
- for (var id in removed) {
- var node = inputs.remove(id);
+ /// [node] doesn't have to be [AssetState.AVAILABLE]. Once it is, the phase
+ /// will automatically begin determining which transforms can consume it as a
+ /// primary input. The transforms themselves won't be applied until [process]
+ /// is called, however.
+ ///
+ /// This should only be used for brand-new assets or assets that have been
+ /// removed and re-created. The phase will automatically handle updated assets
+ /// using the [AssetNode.onStateChange] stream.
+ void addInput(AssetNode node) {
+ // We remove [node.id] from [inputs] as soon as the node is removed rather
+ // than at the same time [node.id] is removed from [_transforms] so we don't
+ // have to wait on [_adjustTransformers]. It's important that [inputs] is
+ // always up-to-date so that the [AssetCascade] can look there for available
+ // assets.
+ inputs[node.id] = node;
+ node.whenRemoved.then((_) => inputs.remove(node.id));
- // Every transform that was using it is dirty now.
- if (node != null) {
- node.consumers.forEach((consumer) => consumer.dirty());
- }
+ if (!_adjustTransformersFutures.containsKey(node.id)) {
+ _transforms[node.id] = new Set<TransformNode>();
+ _adjustTransformers(node);
+ return;
}
- // Update and new or modified assets.
- for (var asset in updated) {
- var node = inputs[asset.id];
- if (node == null) {
- // It's a new node. Add it and remember it so we can see if any new
- // transforms will consume it.
- node = new AssetNode(asset);
- inputs[asset.id] = node;
- _newInputs.add(node);
- } else {
- node.updateAsset(asset);
- }
- }
+ // If an input is added while the same input is still being processed,
+ // that means that the asset was removed and recreated while
+ // [_adjustTransformers] was being run on the old value. We have to wait
+ // until that finishes, then run it again on whatever the newest version
+ // of that asset is.
+
+ // We may already be waiting for the existing [_adjustTransformers] call to
+ // finish. If so, all we need to do is change the node that will be loaded
+ // after it completes.
+ var containedKey = _pendingNewInputs.containsKey(node.id);
+ _pendingNewInputs[node.id] = node;
+ if (containedKey) return;
+
+ // If we aren't already waiting, start doing so.
+ _adjustTransformersFutures[node.id].then((_) {
+ assert(!_adjustTransformersFutures.containsKey(node.id));
+ assert(_pendingNewInputs.containsKey(node.id));
+ _transforms[node.id] = new Set<TransformNode>();
+ _adjustTransformers(_pendingNewInputs.remove(node.id));
+ }, onError: (_) {
+ // If there was a programmatic error while processing the old input,
+ // we don't want to just ignore it; it may have left the system in an
+ // inconsistent state. We also don't want to top-level it, so we
+ // ignore it here but don't start processing the new input. That way
+ // when [process] is called, the error will be piped through its
+ // return value.
+ }).catchError((e) {
+ // If our code above has a programmatic error, ensure it will be piped
+ // through [process] by putting it into [_adjustTransformersFutures].
+ _adjustTransformersFutures[node.id] = new Future.error(e);
+ });
+ }
+
+ /// Returns the input for this phase with the given [id], but only if that
+ /// input is known not to be consumed as a transformer's primary input.
+ ///
+ /// If the input is unavailable, or if the phase hasn't determined whether or
+ /// not any transformers will consume it as a primary input, null will be
+ /// returned instead. This means that the return value is guaranteed to always
+ /// be [AssetState.AVAILABLE].
+ AssetNode getUnconsumedInput(AssetId id) {
+ if (!inputs.containsKey(id)) return null;
+
+ // If the asset has transforms, it's not unconsumed.
+ if (!_transforms[id].isEmpty) return null;
+
+ // If we're working on figuring out if the asset has transforms, we can't
+ // prove that it's unconsumed.
+ if (_adjustTransformersFutures.containsKey(id)) return null;
+
+ // The asset should be available. If it were removed, it wouldn't be in
+ // _inputs, and if it were dirty, it'd be in _adjustTransformersFutures.
+ assert(inputs[id].state.isAvailable);
+ return inputs[id];
+ }
+
+ /// Asynchronously determines which transformers can consume [node] as a
+ /// primary input and creates transforms for them.
+ ///
+ /// This ensures that if [node] is modified or removed during or after the
+ /// time it takes to adjust its transformers, they're appropriately
+ /// re-adjusted. Its progress can be tracked in [_adjustTransformersFutures].
+ void _adjustTransformers(AssetNode node) {
+ // Once the input is available, hook up transformers for it. If it changes
+ // while that's happening, try again.
+ _adjustTransformersFutures[node.id] = node.tryUntilStable((asset) {
+ var oldTransformers = _transforms[node.id]
+ .map((transform) => transform.transformer).toSet();
+
+ return _removeStaleTransforms(asset)
+ .then((_) => _addFreshTransforms(node, oldTransformers));
+ }).then((_) {
+ // Now all the transforms are set up correctly and the asset is available
+ // for the time being. Set up handlers for when the asset changes in the
+ // future.
+ node.onStateChange.first.then((state) {
+ if (state.isRemoved) {
+ _transforms.remove(node.id);
+ } else {
+ _adjustTransformers(node);
+ }
+ }).catchError((e) {
+ _adjustTransformersFutures[node.id] = new Future.error(e);
+ });
+ }).catchError((error) {
+ if (error is! AssetNotFoundException || error.id != node.id) throw error;
+
+ // If the asset is removed, [tryUntilStable] will throw an
+ // [AssetNotFoundException]. In that case, just remove all transforms for
+ // the node.
+ _transforms.remove(node.id);
+ }).whenComplete(() {
+ _adjustTransformersFutures.remove(node.id);
+ });
+
+ // Don't top-level errors coming from the input processing. Any errors will
+ // eventually be piped through [process]'s returned Future.
+ _adjustTransformersFutures[node.id].catchError((_) {});
+ }
+
+ // Remove any old transforms that used to have [asset] as a primary asset but
+ // no longer apply to its new contents.
+ Future _removeStaleTransforms(Asset asset) {
+ return Future.wait(_transforms[asset.id].map((transform) {
+ // TODO(rnystrom): Catch all errors from isPrimary() and redirect to
+ // results.
+ return transform.transformer.isPrimary(asset).then((isPrimary) {
+ if (isPrimary) return;
+ _transforms[asset.id].remove(transform);
+ transform.remove();
+ });
+ }));
+ }
+
+ // Add new transforms for transformers that consider [node]'s asset to be a
+ // primary input.
+ //
+ // [oldTransformers] is the set of transformers that had [node] as a primary
+ // input prior to this. They don't need to be checked, since they were removed
+ // or preserved in [_removeStaleTransforms].
+ Future _addFreshTransforms(AssetNode node, Set<Transformer> oldTransformers) {
+ return Future.wait(_transformers.map((transformer) {
+ if (oldTransformers.contains(transformer)) return new Future.value();
+
+ // If the asset is unavailable, the results of this [_adjustTransformers]
+ // run will be discarded, so we can just short-circuit.
+ if (node.asset == null) return new Future.value();
+
+ // We can safely access [node.asset] here even though it might have
+ // changed since (as above) if it has, [_adjustTransformers] will just be
+ // re-run.
+ // TODO(rnystrom): Catch all errors from isPrimary() and redirect to
+ // results.
+ return transformer.isPrimary(node.asset).then((isPrimary) {
+ if (!isPrimary) return;
+ _transforms[node.id].add(new TransformNode(this, transformer, node));
+ });
+ }));
}
/// Processes this phase.
///
- /// For all new inputs, it tries to see if there are transformers that can
- /// consume them. Then all applicable transforms are applied.
- ///
/// Returns a future that completes when processing is done. If there is
/// nothing to process, returns `null`.
Future process() {
- var future = _processNewInputs();
- if (future == null) {
- return _processTransforms();
- }
-
- return future.then((_) => _processTransforms());
+ if (_adjustTransformersFutures.isEmpty) return _processTransforms();
+ return _waitForInputs().then((_) => _processTransforms());
}
- /// Creates new transforms for any new inputs that are applicable.
- Future _processNewInputs() {
- if (_newInputs.isEmpty) return null;
-
- var futures = [];
- for (var node in _newInputs) {
- for (var transformer in _transformers) {
- // TODO(rnystrom): Catch all errors from isPrimary() and redirect
- // to results.
- futures.add(transformer.isPrimary(node.asset).then((isPrimary) {
- if (!isPrimary) return;
- var transform = new TransformNode(this, transformer, node);
- node.consumers.add(transform);
- _transforms.add(transform);
- }));
- }
- }
-
- _newInputs.clear();
-
- return Future.wait(futures);
+ Future _waitForInputs() {
+ if (_adjustTransformersFutures.isEmpty) return new Future.value();
+ return Future.wait(_adjustTransformersFutures.values)
+ .then((_) => _waitForInputs());
}
/// Applies all currently wired up and dirty transforms.
- ///
- /// Passes their outputs to the next phase.
Future _processTransforms() {
// Convert this to a list so we can safely modify _transforms while
// iterating over it.
- var dirtyTransforms = _transforms.where((transform) => transform.isDirty)
- .toList();
+ var dirtyTransforms =
+ flatten(_transforms.values.map((transforms) => transforms.toList()))
+ .where((transform) => transform.isDirty).toList();
if (dirtyTransforms.isEmpty) return null;
- return Future.wait(dirtyTransforms.map((transform) {
- if (inputs.containsKey(transform.primary.id)) return transform.apply();
+ return Future.wait(dirtyTransforms.map((transform) => transform.apply()))
+ .then((allNewOutputs) {
+ var newOutputs = allNewOutputs.reduce((set1, set2) => set1.union(set2));
- // If the primary input for the transform has been removed, get rid of it
- // and all its outputs.
- _transforms.remove(transform);
- return new Future.value(
- new TransformOutputs(new AssetSet(), transform.outputs));
- })).then((transformOutputs) {
- // Collect all of the outputs. Since the transforms are run in parallel,
- // we have to be careful here to ensure that the result is deterministic
- // and not influenced by the order that transforms complete.
- var updated = new AssetSet();
- var removed = new Set<AssetId>();
var collisions = new Set<AssetId>();
-
- // Handle the generated outputs of all transforms first.
- for (var outputs in transformOutputs) {
- // Collect the outputs of all transformers together.
- for (var asset in outputs.updated) {
- if (updated.containsId(asset.id)) {
- // Report a collision.
- collisions.add(asset.id);
- } else {
- // TODO(rnystrom): In the case of a collision, the asset that
- // "wins" is chosen non-deterministically. Do something better.
- updated.add(asset);
- }
+ for (var newOutput in newOutputs) {
+ if (_outputs.contains(newOutput.id)) {
+ collisions.add(newOutput.id);
+ } else {
+ _next.addInput(newOutput);
+ _outputs.add(newOutput.id);
+ newOutput.whenRemoved.then((_) => _outputs.remove(newOutput.id));
}
-
- // Track any assets no longer output by this transform. We don't
- // handle the case where *another* transform generates the asset
- // no longer generated by this one. updateInputs() handles that.
- removed.addAll(outputs.removed);
}
- // Report any collisions in deterministic order.
+ // Report collisions in a deterministic order.
collisions = collisions.toList();
collisions.sort((a, b) => a.toString().compareTo(b.toString()));
for (var collision in collisions) {
cascade.reportError(new AssetCollisionException(collision));
// TODO(rnystrom): Define what happens after a collision occurs.
}
-
- // Pass the outputs to the next phase.
- _next.updateInputs(updated, removed);
});
}
}
diff --git a/pkg/barback/lib/src/transform.dart b/pkg/barback/lib/src/transform.dart
index cb51753..77800db 100644
--- a/pkg/barback/lib/src/transform.dart
+++ b/pkg/barback/lib/src/transform.dart
@@ -19,9 +19,8 @@
/// Lets [TransformNode] create [Transforms] without giving a [Transform]
/// itself a public constructor, which would be visible to external users.
/// Unlike the [Transform] class, this function is not exported by barback.dart.
-Transform createTransform(TransformNode node, Set<AssetNode> inputs,
- AssetSet outputs) =>
- new Transform._(node, inputs, outputs);
+Transform createTransform(TransformNode node, AssetSet outputs) =>
+ new Transform._(node, outputs);
/// While a [Transformer] represents a *kind* of transformation, this defines
/// one specific usage of it on a set of files.
@@ -33,7 +32,6 @@
class Transform {
final TransformNode _node;
- final Set<AssetNode> _inputs;
final AssetSet _outputs;
/// Gets the ID of the primary input for this transformation.
@@ -50,28 +48,13 @@
/// Gets the asset for the primary input.
Future<Asset> get primaryInput => getInput(primaryId);
- Transform._(this._node, this._inputs, this._outputs);
+ Transform._(this._node, this._outputs);
/// Gets the asset for for an input [id].
///
/// If an input with that ID cannot be found, throws an
/// [AssetNotFoundException].
- Future<Asset> getInput(AssetId id) {
- return newFuture(() {
- var node = _node.phase.inputs[id];
- // TODO(rnystrom): Need to handle passthrough where an asset from a
- // previous phase can be found.
-
- // Throw if the input isn't found. This ensures the transformer's apply
- // is exited. We'll then catch this and report it through the proper
- // results stream.
- if (node == null) throw new MissingInputException(id);
-
- // Keep track of which assets this transform depends on.
- _inputs.add(node);
- return node.asset;
- });
- }
+ Future<Asset> getInput(AssetId id) => _node.getInput(id);
/// Stores [output] as the output created by this transformation.
///
diff --git a/pkg/barback/lib/src/transform_node.dart b/pkg/barback/lib/src/transform_node.dart
index 84e42c0..863bac5 100644
--- a/pkg/barback/lib/src/transform_node.dart
+++ b/pkg/barback/lib/src/transform_node.dart
@@ -14,6 +14,7 @@
import 'phase.dart';
import 'transform.dart';
import 'transformer.dart';
+import 'utils.dart';
/// Describes a transform on a set of assets and its relationship to the build
/// dependency graph.
@@ -25,94 +26,157 @@
final Phase phase;
/// The [Transformer] to apply to this node's inputs.
- final Transformer _transformer;
+ final Transformer transformer;
/// The node for the primary asset this transform depends on.
final AssetNode primary;
+ /// The subscription to [primary]'s [AssetNode.onStateChange] stream.
+ StreamSubscription _primarySubscription;
+
/// True if an input has been modified since the last time this transform
- /// was run.
+ /// began running.
bool get isDirty => _isDirty;
var _isDirty = true;
- /// The inputs read by this transform the last time it was run.
+ /// The subscriptions to each input's [AssetNode.onStateChange] stream.
+ var _inputSubscriptions = new Map<AssetId, StreamSubscription>();
+
+ /// The controllers for the asset nodes emitted by this node.
+ var _outputControllers = new Map<AssetId, AssetNodeController>();
+
+ TransformNode(this.phase, this.transformer, this.primary) {
+ _primarySubscription = primary.onStateChange.listen((state) {
+ if (state.isRemoved) {
+ remove();
+ } else {
+ _dirty();
+ }
+ });
+ }
+
+ /// Marks this transform as removed.
///
- /// Used to tell if an input was removed in a later run.
- var _inputs = new Set<AssetNode>();
-
- /// The outputs created by this transform the last time it was run.
- ///
- /// Used to tell if an output was removed in a later run.
- Set<AssetId> get outputs => _outputs;
- var _outputs = new Set<AssetId>();
-
- TransformNode(this.phase, this._transformer, this.primary);
-
- /// Marks this transform as needing to be run.
- void dirty() {
+ /// This causes all of the transform's outputs to be marked as removed as
+ /// well. Normally this will be automatically done internally based on events
+ /// from the primary input, but it's possible for a transform to no longer be
+ /// valid even if its primary input still exists.
+ void remove() {
_isDirty = true;
+ _primarySubscription.cancel();
+ for (var subscription in _inputSubscriptions.values) {
+ subscription.cancel();
+ }
+ for (var controller in _outputControllers.values) {
+ controller.setRemoved();
+ }
+ }
+
+ /// Marks this transform as dirty.
+ ///
+ /// This causes all of the transform's outputs to be marked as dirty as well.
+ void _dirty() {
+ _isDirty = true;
+ for (var controller in _outputControllers.values) {
+ controller.setDirty();
+ }
}
/// Applies this transform.
///
- /// Returns a [TransformOutputs] describing the resulting outputs compared to
- /// previous runs.
- Future<TransformOutputs> apply() {
- var newInputs = new Set<AssetNode>();
+ /// Returns a set of asset nodes representing the outputs from this transform
+ /// that weren't emitted last time it was run.
+ Future<Set<AssetNode>> apply() {
var newOutputs = new AssetSet();
- var transform = createTransform(this, newInputs, newOutputs);
- return _transformer.apply(transform).catchError((error) {
- // Catch all transformer errors and pipe them to the results stream. This
- // is so a broken transformer doesn't take down the whole graph.
+ var transform = createTransform(this, newOutputs);
+
+ // Clear all the old input subscriptions. If an input is re-used, we'll
+ // re-subscribe.
+ for (var subscription in _inputSubscriptions.values) {
+ subscription.cancel();
+ }
+ _inputSubscriptions.clear();
+
+ _isDirty = false;
+ return transformer.apply(transform).catchError((error) {
+ // If the transform became dirty while processing, ignore any errors from
+ // it.
+ if (_isDirty) return;
+
+ // Catch all transformer errors and pipe them to the results stream.
+ // This is so a broken transformer doesn't take down the whole graph.
phase.cascade.reportError(error);
// Don't allow partial results from a failed transform.
newOutputs.clear();
}).then((_) {
- _isDirty = false;
+ if (_isDirty) return [];
- // Stop watching any inputs that were removed.
- for (var oldInput in _inputs) {
- oldInput.consumers.remove(this);
- }
-
- // Watch any new inputs so this transform will be re-processed when an
- // input is modified.
- for (var newInput in newInputs) {
- newInput.consumers.add(this);
- }
-
- _inputs = newInputs;
-
- // See which outputs are missing from the last run.
- var outputIds = newOutputs.map((asset) => asset.id).toSet();
- var invalidIds = outputIds
- .where((id) => id.package != phase.cascade.package).toSet();
- outputIds.removeAll(invalidIds);
-
- for (var id in invalidIds) {
- // TODO(nweiz): report this as a warning rather than a failing error.
- phase.cascade.reportError(
- new InvalidOutputException(phase.cascade.package, id));
- }
-
- var removed = _outputs.difference(outputIds);
- _outputs = outputIds;
-
- return new TransformOutputs(newOutputs, removed);
+ return _adjustOutputs(newOutputs);
});
}
-}
-/// The result of running a [Transform], compared to the previous time it was
-/// applied.
-class TransformOutputs {
- /// The outputs that are new or were modified since the last run.
- final AssetSet updated;
+ Future<Asset> getInput(AssetId id) {
+ return newFuture(() {
+ var node = phase.inputs[id];
+ // TODO(rnystrom): Need to handle passthrough where an asset from a
+ // previous phase can be found.
- /// The outputs that were created by the previous run but were not generated
- /// by the most recent run.
- final Set<AssetId> removed;
+ // Throw if the input isn't found. This ensures the transformer's apply
+ // is exited. We'll then catch this and report it through the proper
+ // results stream.
+ if (node == null) throw new MissingInputException(id);
- TransformOutputs(this.updated, this.removed);
+ // If the asset node is found, wait until its contents are actually
+ // available before we return them.
+ return node.whenAvailable.then((asset) {
+ _inputSubscriptions.putIfAbsent(node.id,
+ () => node.onStateChange.listen((_) => _dirty()));
+
+ return asset;
+ }).catchError((error) {
+ if (error is! AssetNotFoundException || error.id != id) throw error;
+ // If the node was removed before it could be loaded, treat it as though
+ // it never existed and throw a MissingInputException.
+ throw new MissingInputException(id);
+ });
+ });
+ }
+
+ /// Adjusts the outputs of the transform to reflect the outputs emitted on its
+ /// most recent run.
+ Set<AssetNode> _adjustOutputs(AssetSet newOutputs) {
+ // Any ids that are for a different package are invalid.
+ var invalidIds = newOutputs
+ .map((asset) => asset.id)
+ .where((id) => id.package != phase.cascade.package)
+ .toSet();
+ for (var id in invalidIds) {
+ newOutputs.removeId(id);
+ // TODO(nweiz): report this as a warning rather than a failing error.
+ phase.cascade.reportError(
+ new InvalidOutputException(phase.cascade.package, id));
+ }
+
+ // Remove outputs that used to exist but don't anymore.
+ for (var id in _outputControllers.keys.toList()) {
+ if (newOutputs.containsId(id)) continue;
+ _outputControllers.remove(id).setRemoved();
+ }
+
+ var brandNewOutputs = new Set<AssetNode>();
+ // Store any new outputs or new contents for existing outputs.
+ for (var asset in newOutputs) {
+ var controller = _outputControllers[asset.id];
+ if (controller != null) {
+ controller.setAvailable(asset);
+ } else {
+ var controller = new AssetNodeController.available(asset);
+ _outputControllers[asset.id] = controller;
+ brandNewOutputs.add(controller.node);
+ }
+ }
+
+ return brandNewOutputs;
+ }
}
diff --git a/pkg/barback/test/asset_set_test.dart b/pkg/barback/test/asset_set_test.dart
index 6cb1eb8..5b6b652 100644
--- a/pkg/barback/test/asset_set_test.dart
+++ b/pkg/barback/test/asset_set_test.dart
@@ -18,11 +18,25 @@
var fooId = new AssetId.parse("app|foo.txt");
var barId = new AssetId.parse("app|bar.txt");
+ var bazId = new AssetId.parse("app|baz.txt");
+
+ group(".from()", () {
+ test("creates a set from an iterable", () {
+ var set = new AssetSet.from([
+ new Asset.fromString(fooId, "foo"),
+ new Asset.fromString(barId, "bar")
+ ]);
+
+ expect(set.containsId(fooId), isTrue);
+ expect(set.containsId(barId), isTrue);
+ expect(set.containsId(bazId), isFalse);
+ });
+ });
group("[] operator", () {
test("gets an asset with the given ID", () {
var set = new AssetSet();
- var foo = new MockAsset(fooId, "foo");
+ var foo = new Asset.fromString(fooId, "foo");
set.add(foo);
expect(set[fooId], equals(foo));
@@ -37,21 +51,21 @@
group(".add()", () {
test("adds the asset to the set", () {
var set = new AssetSet();
- var foo = new MockAsset(fooId, "foo");
+ var foo = new Asset.fromString(fooId, "foo");
set.add(foo);
expect(set.contains(foo), isTrue);
});
test("replaces a previously added asset with that ID", () {
var set = new AssetSet();
- set.add(new MockAsset(fooId, "before"));
- set.add(new MockAsset(fooId, "after"));
- expect(set[fooId].contents, equals("after"));
+ set.add(new Asset.fromString(fooId, "before"));
+ set.add(new Asset.fromString(fooId, "after"));
+ expect(set[fooId].readAsString(), completion(equals("after")));
});
test("returns the added item", () {
var set = new AssetSet();
- var foo = new MockAsset(fooId, "foo");
+ var foo = new Asset.fromString(fooId, "foo");
expect(set.add(foo), equals(foo));
});
});
@@ -59,8 +73,8 @@
group(".addAll()", () {
test("adds the assets to the set", () {
var set = new AssetSet();
- var foo = new MockAsset(fooId, "foo");
- var bar = new MockAsset(barId, "bar");
+ var foo = new Asset.fromString(fooId, "foo");
+ var bar = new Asset.fromString(barId, "bar");
set.addAll([foo, bar]);
expect(set.contains(foo), isTrue);
expect(set.contains(bar), isTrue);
@@ -68,17 +82,17 @@
test("replaces assets earlier in the sequence with later ones", () {
var set = new AssetSet();
- var foo1 = new MockAsset(fooId, "before");
- var foo2 = new MockAsset(fooId, "after");
+ var foo1 = new Asset.fromString(fooId, "before");
+ var foo2 = new Asset.fromString(fooId, "after");
set.addAll([foo1, foo2]);
- expect(set[fooId].contents, equals("after"));
+ expect(set[fooId].readAsString(), completion(equals("after")));
});
});
group(".clear()", () {
test("empties the set", () {
var set = new AssetSet();
- var foo = new MockAsset(fooId, "foo");
+ var foo = new Asset.fromString(fooId, "foo");
set.add(foo);
set.clear();
@@ -90,8 +104,8 @@
group(".contains()", () {
test("returns true if the asset is in the set", () {
var set = new AssetSet();
- var foo = new MockAsset(fooId, "foo");
- var bar = new MockAsset(barId, "bar");
+ var foo = new Asset.fromString(fooId, "foo");
+ var bar = new Asset.fromString(barId, "bar");
set.add(foo);
expect(set.contains(foo), isTrue);
@@ -102,11 +116,38 @@
group(".containsId()", () {
test("returns true if an asset with the ID is in the set", () {
var set = new AssetSet();
- var foo = new MockAsset(fooId, "foo");
+ var foo = new Asset.fromString(fooId, "foo");
set.add(foo);
expect(set.containsId(fooId), isTrue);
expect(set.containsId(barId), isFalse);
});
});
+
+ group(".removeId()", () {
+ test("removes the asset with the ID from the set", () {
+ var set = new AssetSet();
+ var foo = new Asset.fromString(fooId, "foo");
+ set.add(foo);
+
+ set.removeId(fooId);
+ expect(set.containsId(fooId), isFalse);
+ });
+
+ test("returns the removed asset", () {
+ var set = new AssetSet();
+ var foo = new Asset.fromString(fooId, "foo");
+ set.add(foo);
+
+ expect(set.removeId(fooId).readAsString(), completion(equals("foo")));
+ });
+
+ test("returns null when removing an asset not in the set", () {
+ var set = new AssetSet();
+ var foo = new Asset.fromString(fooId, "foo");
+ set.add(foo);
+
+ expect(set.removeId(barId), isNull);
+ });
+ });
}
diff --git a/pkg/barback/test/cancelable_future_test.dart b/pkg/barback/test/cancelable_future_test.dart
new file mode 100644
index 0000000..d5f9ae4
--- /dev/null
+++ b/pkg/barback/test/cancelable_future_test.dart
@@ -0,0 +1,62 @@
+// Copyright (c) 2013, 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 barback.test.cancelable_future_test;
+
+import 'dart:async';
+
+import 'package:barback/src/cancelable_future.dart';
+import 'package:barback/src/utils.dart';
+import 'package:unittest/unittest.dart';
+
+import 'utils.dart';
+
+main() {
+ initConfig();
+
+ var completer;
+ var future;
+ setUp(() {
+ completer = new Completer();
+ future = new CancelableFuture(completer.future);
+ });
+
+ group("when not canceled", () {
+ test("correctly completes successfully", () {
+ expect(future, completion(equals("success")));
+ completer.complete("success");
+ });
+
+ test("correctly completes with an error", () {
+ expect(future, throwsA(equals("error")));
+ completer.completeError("error");
+ });
+ });
+
+ group("when canceled", () {
+ test("never completes successfully", () {
+ var completed = false;
+ future.whenComplete(() {
+ completed = true;
+ });
+
+ future.cancel();
+ completer.complete("success");
+
+ expect(pumpEventQueue().then((_) => completed), completion(isFalse));
+ });
+
+ test("never completes with an error", () {
+ var completed = false;
+ future.catchError((_) {}).whenComplete(() {
+ completed = true;
+ });
+
+ future.cancel();
+ completer.completeError("error");
+
+ expect(pumpEventQueue().then((_) => completed), completion(isFalse));
+ });
+ });
+}
diff --git a/pkg/barback/test/package_graph/errors_test.dart b/pkg/barback/test/package_graph/errors_test.dart
index 0653022..973155b 100644
--- a/pkg/barback/test/package_graph/errors_test.dart
+++ b/pkg/barback/test/package_graph/errors_test.dart
@@ -26,6 +26,22 @@
buildShouldFail([isAssetCollisionException("app|foo.b")]);
});
+ test("errors if a new transformer outputs the same file as an old "
+ "transformer", () {
+ initGraph(["app|foo.a", "app|foo.b"], {"app": [
+ [
+ new RewriteTransformer("a", "c"),
+ new RewriteTransformer("b", "c")
+ ]
+ ]});
+ updateSources(["app|foo.a"]);
+ expectAsset("app|foo.c", "foo.c");
+ buildShouldSucceed();
+
+ schedule(() => updateSources(["app|foo.b"]));
+ buildShouldFail([isAssetCollisionException("app|foo.c")]);
+ });
+
test("does not report asset not found errors in results", () {
initGraph(["app|bar.txt"]);
@@ -107,9 +123,7 @@
buildShouldFail([equals(BadTransformer.ERROR)]);
});
- // TODO(rnystrom): Is this the behavior we expect? If a transformer fails
- // to transform a file, should we just skip past it to the source?
- test("yields a source if a transform fails on it", () {
+ test("doesn't yield a source if a transform fails on it", () {
initGraph(["app|foo.txt"], {"app": [
[new BadTransformer(["app|foo.txt"])]
]});
@@ -118,7 +132,7 @@
updateSources(["app|foo.txt"]);
});
- expectAsset("app|foo.txt");
+ expectNoAsset("app|foo.txt");
});
test("catches errors even if nothing is waiting for process results", () {
@@ -172,4 +186,13 @@
equals(BadTransformer.ERROR)
]);
});
+
+ test("an error loading an asset removes the asset from the graph", () {
+ initGraph(["app|foo.txt"]);
+
+ setAssetError("app|foo.txt");
+ schedule(() => updateSources(["app|foo.txt"]));
+ expectNoAsset("app|foo.txt");
+ buildShouldFail([isMockLoadException("app|foo.txt")]);
+ });
}
diff --git a/pkg/barback/test/package_graph/source_test.dart b/pkg/barback/test/package_graph/source_test.dart
index 0185679..e6627e7 100644
--- a/pkg/barback/test/package_graph/source_test.dart
+++ b/pkg/barback/test/package_graph/source_test.dart
@@ -7,6 +7,7 @@
import 'dart:async';
import 'package:barback/barback.dart';
+import 'package:barback/src/utils.dart';
import 'package:scheduled_test/scheduled_test.dart';
import '../utils.dart';
@@ -112,6 +113,24 @@
buildShouldSucceed();
});
+ test("reloads an asset that's updated while loading", () {
+ initGraph({"app|foo.txt": "foo"});
+
+ pauseProvider();
+ schedule(() {
+ // The mock provider synchronously loads the value of the assets, so this
+ // will kick off two loads with different values. The second one should
+ // win.
+ updateSources(["app|foo.txt"]);
+ modifyAsset("app|foo.txt", "bar");
+ updateSources(["app|foo.txt"]);
+ });
+
+ resumeProvider();
+ expectAsset("app|foo.txt", "bar");
+ buildShouldSucceed();
+ });
+
test("restarts a build if a source is updated while sources are loading", () {
var transformer = new RewriteTransformer("txt", "out");
initGraph(["app|foo.txt", "app|other.bar"], {"app": [[transformer]]});
diff --git a/pkg/barback/test/package_graph/transform_test.dart b/pkg/barback/test/package_graph/transform_test.dart
index bcb7c33..670848a 100644
--- a/pkg/barback/test/package_graph/transform_test.dart
+++ b/pkg/barback/test/package_graph/transform_test.dart
@@ -7,6 +7,7 @@
import 'dart:async';
import 'package:barback/barback.dart';
+import 'package:barback/src/utils.dart';
import 'package:scheduled_test/scheduled_test.dart';
import '../utils.dart';
@@ -104,8 +105,8 @@
var transformerB = new RewriteTransformer("txt", "b");
initGraph(["app|foo.txt"], {"app": [[transformerA, transformerB]]});
- transformerA.wait();
- transformerB.wait();
+ transformerA.pauseApply();
+ transformerB.pauseApply();
schedule(() {
updateSources(["app|foo.txt"]);
@@ -119,8 +120,8 @@
expect(transformerA.isRunning, isTrue);
expect(transformerB.isRunning, isTrue);
- transformerA.complete();
- transformerB.complete();
+ transformerA.resumeApply();
+ transformerB.resumeApply();
});
expectAsset("app|foo.a", "foo.a");
@@ -128,6 +129,18 @@
buildShouldSucceed();
});
+ test("outputs are inaccessible once used", () {
+ initGraph(["app|foo.a"], {"app": [
+ [new RewriteTransformer("a", "b")],
+ [new RewriteTransformer("a", "c")]
+ ]});
+ updateSources(["app|foo.a"]);
+ expectAsset("app|foo.b", "foo.b");
+ expectNoAsset("app|foo.a");
+ expectNoAsset("app|foo.c");
+ buildShouldSucceed();
+ });
+
test("does not reapply transform when inputs are not modified", () {
var transformer = new RewriteTransformer("blub", "blab");
initGraph(["app|foo.blub"], {"app": [[transformer]]});
@@ -186,10 +199,8 @@
buildShouldSucceed();
// Remove the dependency on the non-primary input.
- schedule(() {
- modifyAsset("app|a.txt", "a.inc");
- updateSources(["app|a.txt"]);
- });
+ modifyAsset("app|a.txt", "a.inc");
+ schedule(() => updateSources(["app|a.txt"]));
// Process it again.
expectAsset("app|a.out", "a");
@@ -269,8 +280,25 @@
buildShouldSucceed();
});
+ test("discards outputs from a transform whose primary input is removed "
+ "during processing", () {
+ var rewrite = new RewriteTransformer("txt", "out");
+ initGraph(["app|foo.txt"], {"app": [[rewrite]]});
+
+ rewrite.pauseApply();
+ updateSources(["app|foo.txt"]);
+ schedule(() => rewrite.started);
+ schedule(() {
+ removeSources(["app|foo.txt"]);
+ rewrite.resumeApply();
+ });
+
+ expectNoAsset("app|foo.out");
+ buildShouldSucceed();
+ });
+
test("reapplies a transform when a non-primary input changes", () {
- initGraph({
+ initGraph({
"app|a.txt": "a.inc",
"app|a.inc": "a"
}, {"app": [[new ManyToOneTransformer("txt")]]});
@@ -279,20 +307,81 @@
expectAsset("app|a.out", "a");
buildShouldSucceed();
- schedule(() {
- modifyAsset("app|a.inc", "after");
- updateSources(["app|a.inc"]);
- });
+ modifyAsset("app|a.inc", "after");
+ schedule(() => updateSources(["app|a.inc"]));
expectAsset("app|a.out", "after");
buildShouldSucceed();
});
+ test("applies a transform when it becomes newly primary", () {
+ initGraph({
+ "app|foo.txt": "this",
+ }, {"app": [[new CheckContentTransformer("that", " and the other")]]});
+
+ updateSources(["app|foo.txt"]);
+ expectAsset("app|foo.txt", "this");
+ buildShouldSucceed();
+
+ modifyAsset("app|foo.txt", "that");
+ schedule(() => updateSources(["app|foo.txt"]));
+
+ expectAsset("app|foo.txt", "that and the other");
+ buildShouldSucceed();
+ });
+
+ test("applies the correct transform if an asset is modified during isPrimary",
+ () {
+ var check1 = new CheckContentTransformer("first", "#1");
+ var check2 = new CheckContentTransformer("second", "#2");
+ initGraph({
+ "app|foo.txt": "first",
+ }, {"app": [[check1, check2]]});
+
+ check1.pauseIsPrimary("app|foo.txt");
+ updateSources(["app|foo.txt"]);
+ // Ensure that we're waiting on check1's isPrimary.
+ schedule(pumpEventQueue);
+
+ modifyAsset("app|foo.txt", "second");
+ schedule(() {
+ updateSources(["app|foo.txt"]);
+ check1.resumeIsPrimary("app|foo.txt");
+ });
+
+ expectAsset("app|foo.txt", "second#2");
+ buildShouldSucceed();
+ });
+
+ test("applies the correct transform if an asset is removed and added during "
+ "isPrimary", () {
+ var check1 = new CheckContentTransformer("first", "#1");
+ var check2 = new CheckContentTransformer("second", "#2");
+ initGraph({
+ "app|foo.txt": "first",
+ }, {"app": [[check1, check2]]});
+
+ check1.pauseIsPrimary("app|foo.txt");
+ updateSources(["app|foo.txt"]);
+ // Ensure that we're waiting on check1's isPrimary.
+ schedule(pumpEventQueue);
+
+ schedule(() => removeSources(["app|foo.txt"]));
+ modifyAsset("app|foo.txt", "second");
+ schedule(() {
+ updateSources(["app|foo.txt"]);
+ check1.resumeIsPrimary("app|foo.txt");
+ });
+
+ expectAsset("app|foo.txt", "second#2");
+ buildShouldSucceed();
+ });
+
test("restarts processing if a change occurs during processing", () {
var transformer = new RewriteTransformer("txt", "out");
initGraph(["app|foo.txt"], {"app": [[transformer]]});
- transformer.wait();
+ transformer.pauseApply();
schedule(() {
updateSources(["app|foo.txt"]);
@@ -304,10 +393,7 @@
schedule(() {
// Now update the graph during it.
updateSources(["app|foo.txt"]);
- });
-
- schedule(() {
- transformer.complete();
+ transformer.resumeApply();
});
expectAsset("app|foo.out", "foo.out");
@@ -318,6 +404,108 @@
});
});
+ test("aborts processing if the primary input is removed during processing",
+ () {
+ var transformer = new RewriteTransformer("txt", "out");
+ initGraph(["app|foo.txt"], {"app": [[transformer]]});
+
+ transformer.pauseApply();
+
+ schedule(() {
+ updateSources(["app|foo.txt"]);
+
+ // Wait for the transform to start.
+ return transformer.started;
+ });
+
+ schedule(() {
+ // Now remove its primary input while it's running.
+ removeSources(["app|foo.txt"]);
+ transformer.resumeApply();
+ });
+
+ expectNoAsset("app|foo.out");
+ buildShouldSucceed();
+
+ schedule(() {
+ expect(transformer.numRuns, equals(1));
+ });
+ });
+
+ test("restarts processing if a change to a new secondary input occurs during "
+ "processing", () {
+ var transformer = new ManyToOneTransformer("txt");
+ initGraph({
+ "app|foo.txt": "bar.inc",
+ "app|bar.inc": "bar"
+ }, {"app": [[transformer]]});
+
+ transformer.pauseApply();
+
+ updateSources(["app|foo.txt", "app|bar.inc"]);
+ // Wait for the transform to start.
+ schedule(() => transformer.started);
+
+ // Give the transform time to load bar.inc the first time.
+ schedule(pumpEventQueue);
+
+ // Now update the secondary input before the transform finishes.
+ modifyAsset("app|bar.inc", "baz");
+ schedule(() => updateSources(["app|bar.inc"]));
+ // Give bar.inc enough time to be loaded and marked available before the
+ // transformer completes.
+ schedule(pumpEventQueue);
+
+ schedule(transformer.resumeApply);
+
+ expectAsset("app|foo.out", "baz");
+ buildShouldSucceed();
+
+ schedule(() {
+ expect(transformer.numRuns, equals(2));
+ });
+ });
+
+ test("doesn't restart processing if a change to an old secondary input "
+ "occurs during processing", () {
+ var transformer = new ManyToOneTransformer("txt");
+ initGraph({
+ "app|foo.txt": "bar.inc",
+ "app|bar.inc": "bar",
+ "app|baz.inc": "baz"
+ }, {"app": [[transformer]]});
+
+ updateSources(["app|foo.txt", "app|bar.inc", "app|baz.inc"]);
+ expectAsset("app|foo.out", "bar");
+ buildShouldSucceed();
+
+ schedule(transformer.pauseApply);
+ modifyAsset("app|foo.txt", "baz.inc");
+ schedule(() {
+ updateSources(["app|foo.txt"]);
+ // Wait for the transform to start.
+ return transformer.started;
+ });
+
+ // Now update the old secondary input before the transform finishes.
+ modifyAsset("app|bar.inc", "new bar");
+ schedule(() => updateSources(["app|bar.inc"]));
+ // Give bar.inc enough time to be loaded and marked available before the
+ // transformer completes.
+ schedule(pumpEventQueue);
+
+ schedule(transformer.resumeApply);
+
+ expectAsset("app|foo.out", "baz");
+ buildShouldSucceed();
+
+ schedule(() {
+ // Should have run once the first time, then again when switching to
+ // baz.inc. Should not run a third time because of bar.inc being modified.
+ expect(transformer.numRuns, equals(2));
+ });
+ });
+
test("handles an output moving from one transformer to another", () {
// In the first run, "shared.out" is created by the "a.a" transformer.
initGraph({
@@ -336,11 +524,9 @@
// Now switch their contents so that "shared.out" will be output by "b.b"'s
// transformer.
- schedule(() {
- modifyAsset("app|a.a", "a.out");
- modifyAsset("app|b.b", "b.out,shared.out");
- updateSources(["app|a.a", "app|b.b"]);
- });
+ modifyAsset("app|a.a", "a.out");
+ modifyAsset("app|b.b", "b.out,shared.out");
+ schedule(() => updateSources(["app|a.a", "app|b.b"]));
expectAsset("app|a.out", "spread a");
expectAsset("app|b.out", "spread b");
@@ -354,7 +540,7 @@
initGraph(["app|foo.txt", "app|bar.txt"],
{"app": [[txtToInt], [intToOut]]});
- txtToInt.wait();
+ txtToInt.pauseApply();
schedule(() {
updateSources(["app|foo.txt"]);
@@ -369,7 +555,7 @@
});
schedule(() {
- txtToInt.complete();
+ txtToInt.resumeApply();
});
expectAsset("app|foo.out", "foo.int.out");
@@ -408,6 +594,281 @@
buildShouldSucceed();
});
+ test("doesn't return an asset until it's finished rebuilding", () {
+ initGraph(["app|foo.in"], {"app": [
+ [new RewriteTransformer("in", "mid")],
+ [new RewriteTransformer("mid", "out")]
+ ]});
+
+ updateSources(["app|foo.in"]);
+ expectAsset("app|foo.out", "foo.mid.out");
+ buildShouldSucceed();
+
+ pauseProvider();
+ modifyAsset("app|foo.in", "new");
+ schedule(() => updateSources(["app|foo.in"]));
+ expectAssetDoesNotComplete("app|foo.out");
+ buildShouldNotBeDone();
+
+ resumeProvider();
+ expectAsset("app|foo.out", "new.mid.out");
+ buildShouldSucceed();
+ });
+
+ test("doesn't return an asset until its in-place transform is done", () {
+ var rewrite = new RewriteTransformer("txt", "txt");
+ initGraph(["app|foo.txt"], {"app": [[rewrite]]});
+
+ rewrite.pauseApply();
+ updateSources(["app|foo.txt"]);
+ expectAssetDoesNotComplete("app|foo.txt");
+
+ schedule(rewrite.resumeApply);
+ expectAsset("app|foo.txt", "foo.txt");
+ buildShouldSucceed();
+ });
+
+ test("doesn't return an asset until we know it won't be transformed",
+ () {
+ var rewrite = new RewriteTransformer("txt", "txt");
+ initGraph(["app|foo.a"], {"app": [[rewrite]]});
+
+ rewrite.pauseIsPrimary("app|foo.a");
+ updateSources(["app|foo.a"]);
+ expectAssetDoesNotComplete("app|foo.a");
+
+ schedule(() => rewrite.resumeIsPrimary("app|foo.a"));
+ expectAsset("app|foo.a", "foo");
+ buildShouldSucceed();
+ });
+
+ test("doesn't return a modified asset until we know it will still be "
+ "transformed", () {
+ var rewrite = new RewriteTransformer("txt", "txt");
+ initGraph(["app|foo.txt"], {"app": [[rewrite]]});
+
+ updateSources(["app|foo.txt"]);
+ expectAsset("app|foo.txt", "foo.txt");
+ buildShouldSucceed();
+
+ schedule(() => rewrite.pauseIsPrimary("app|foo.txt"));
+ schedule(() => updateSources(["app|foo.txt"]));
+ expectAssetDoesNotComplete("app|foo.txt");
+
+ schedule(() => rewrite.resumeIsPrimary("app|foo.txt"));
+ expectAsset("app|foo.txt", "foo.txt");
+ buildShouldSucceed();
+ });
+
+ test("doesn't return an asset that's removed during isPrimary", () {
+ var rewrite = new RewriteTransformer("txt", "txt");
+ initGraph(["app|foo.txt"], {"app": [[rewrite]]});
+
+ rewrite.pauseIsPrimary("app|foo.txt");
+ updateSources(["app|foo.txt"]);
+ // Make sure we're waiting on isPrimary.
+ schedule(pumpEventQueue);
+
+ schedule(() {
+ removeSources(["app|foo.txt"]);
+ rewrite.resumeIsPrimary("app|foo.txt");
+ });
+ expectNoAsset("app|foo.txt");
+ buildShouldSucceed();
+ });
+
+ test("doesn't transform an asset that goes from primary to non-primary "
+ "during isPrimary", () {
+ var check = new CheckContentTransformer("do", "ne");
+ initGraph({
+ "app|foo.txt": "do"
+ }, {"app": [[check]]});
+
+ check.pauseIsPrimary("app|foo.txt");
+ updateSources(["app|foo.txt"]);
+ // Make sure we're waiting on isPrimary.
+ schedule(pumpEventQueue);
+
+ modifyAsset("app|foo.txt", "don't");
+ schedule(() {
+ updateSources(["app|foo.txt"]);
+ check.resumeIsPrimary("app|foo.txt");
+ });
+
+ expectAsset("app|foo.txt", "don't");
+ buildShouldSucceed();
+ });
+
+ test("transforms an asset that goes from non-primary to primary "
+ "during isPrimary", () {
+ var check = new CheckContentTransformer("do", "ne");
+ initGraph({
+ "app|foo.txt": "don't"
+ }, {"app": [[check]]});
+
+ check.pauseIsPrimary("app|foo.txt");
+ updateSources(["app|foo.txt"]);
+ // Make sure we're waiting on isPrimary.
+ schedule(pumpEventQueue);
+
+ modifyAsset("app|foo.txt", "do");
+ schedule(() {
+ updateSources(["app|foo.txt"]);
+ check.resumeIsPrimary("app|foo.txt");
+ });
+
+ expectAsset("app|foo.txt", "done");
+ buildShouldSucceed();
+ });
+
+ test("doesn't return an asset that's removed during another transformer's "
+ "isPrimary", () {
+ var rewrite1 = new RewriteTransformer("txt", "txt");
+ var rewrite2 = new RewriteTransformer("md", "md");
+ initGraph(["app|foo.txt", "app|foo.md"], {"app": [[rewrite1, rewrite2]]});
+
+ rewrite2.pauseIsPrimary("app|foo.md");
+ updateSources(["app|foo.txt", "app|foo.md"]);
+ // Make sure we're waiting on the correct isPrimary.
+ schedule(pumpEventQueue);
+
+ schedule(() {
+ removeSources(["app|foo.txt"]);
+ rewrite2.resumeIsPrimary("app|foo.md");
+ });
+ expectNoAsset("app|foo.txt");
+ expectAsset("app|foo.md", "foo.md");
+ buildShouldSucceed();
+ });
+
+ test("doesn't transform an asset that goes from primary to non-primary "
+ "during another transformer's isPrimary", () {
+ var rewrite = new RewriteTransformer("md", "md");
+ var check = new CheckContentTransformer("do", "ne");
+ initGraph({
+ "app|foo.txt": "do",
+ "app|foo.md": "foo"
+ }, {"app": [[rewrite, check]]});
+
+ rewrite.pauseIsPrimary("app|foo.md");
+ updateSources(["app|foo.txt", "app|foo.md"]);
+ // Make sure we're waiting on the correct isPrimary.
+ schedule(pumpEventQueue);
+
+ modifyAsset("app|foo.txt", "don't");
+ schedule(() {
+ updateSources(["app|foo.txt"]);
+ rewrite.resumeIsPrimary("app|foo.md");
+ });
+
+ expectAsset("app|foo.txt", "don't");
+ expectAsset("app|foo.md", "foo.md");
+ buildShouldSucceed();
+ });
+
+ test("transforms an asset that goes from non-primary to primary "
+ "during another transformer's isPrimary", () {
+ var rewrite = new RewriteTransformer("md", "md");
+ var check = new CheckContentTransformer("do", "ne");
+ initGraph({
+ "app|foo.txt": "don't",
+ "app|foo.md": "foo"
+ }, {"app": [[rewrite, check]]});
+
+ rewrite.pauseIsPrimary("app|foo.md");
+ updateSources(["app|foo.txt", "app|foo.md"]);
+ // Make sure we're waiting on the correct isPrimary.
+ schedule(pumpEventQueue);
+
+ modifyAsset("app|foo.txt", "do");
+ schedule(() {
+ updateSources(["app|foo.txt"]);
+ rewrite.resumeIsPrimary("app|foo.md");
+ });
+
+ expectAsset("app|foo.txt", "done");
+ expectAsset("app|foo.md", "foo.md");
+ buildShouldSucceed();
+ });
+
+ test("removes pipelined transforms when the root primary input is removed",
+ () {
+ initGraph(["app|foo.txt"], {"app": [
+ [new RewriteTransformer("txt", "mid")],
+ [new RewriteTransformer("mid", "out")]
+ ]});
+
+ updateSources(["app|foo.txt"]);
+ expectAsset("app|foo.out", "foo.mid.out");
+ buildShouldSucceed();
+
+ schedule(() => removeSources(["app|foo.txt"]));
+ expectNoAsset("app|foo.out");
+ buildShouldSucceed();
+ });
+
+ test("removes pipelined transforms when the parent ceases to generate the "
+ "primary input", () {
+ initGraph({"app|foo.txt": "foo.mid"}, {'app': [
+ [new OneToManyTransformer('txt')],
+ [new RewriteTransformer('mid', 'out')]
+ ]});
+
+ updateSources(['app|foo.txt']);
+ expectAsset('app|foo.out', 'spread txt.out');
+ buildShouldSucceed();
+
+ modifyAsset("app|foo.txt", "bar.mid");
+ schedule(() => updateSources(["app|foo.txt"]));
+ expectNoAsset('app|foo.out');
+ expectAsset('app|bar.out', 'spread txt.out');
+ buildShouldSucceed();
+ });
+
+ test("returns an asset even if an unrelated build is running", () {
+ initGraph([
+ "app|foo.in",
+ "app|bar.in",
+ ], {"app": [[new RewriteTransformer("in", "out")]]});
+
+ updateSources(["app|foo.in", "app|bar.in"]);
+ expectAsset("app|foo.out", "foo.out");
+ expectAsset("app|bar.out", "bar.out");
+ buildShouldSucceed();
+
+ pauseProvider();
+ modifyAsset("app|foo.in", "new");
+ schedule(() => updateSources(["app|foo.in"]));
+ expectAssetDoesNotComplete("app|foo.out");
+ expectAsset("app|bar.out", "bar.out");
+ buildShouldNotBeDone();
+
+ resumeProvider();
+ expectAsset("app|foo.out", "new.out");
+ buildShouldSucceed();
+ });
+
+ test("doesn't report AssetNotFound until all builds are finished", () {
+ initGraph([
+ "app|foo.in",
+ ], {"app": [[new RewriteTransformer("in", "out")]]});
+
+ updateSources(["app|foo.in"]);
+ expectAsset("app|foo.out", "foo.out");
+ buildShouldSucceed();
+
+ pauseProvider();
+ schedule(() => updateSources(["app|foo.in"]));
+ expectAssetDoesNotComplete("app|foo.out");
+ expectAssetDoesNotComplete("app|non-existent.out");
+ buildShouldNotBeDone();
+
+ resumeProvider();
+ expectAsset("app|foo.out", "foo.out");
+ expectNoAsset("app|non-existent.out");
+ buildShouldSucceed();
+ });
+
test("doesn't emit a result until all builds are finished", () {
var rewrite = new RewriteTransformer("txt", "out");
initGraph([
diff --git a/pkg/barback/test/transformer/bad.dart b/pkg/barback/test/transformer/bad.dart
new file mode 100644
index 0000000..49046ca
--- /dev/null
+++ b/pkg/barback/test/transformer/bad.dart
@@ -0,0 +1,39 @@
+// Copyright (c) 2013, 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 barback.test.transformer.bad;
+
+import 'dart:async';
+
+import 'package:barback/barback.dart';
+import 'package:barback/src/utils.dart';
+
+import 'mock.dart';
+
+/// A transformer that throws an exception when run, after generating the
+/// given outputs.
+class BadTransformer extends MockTransformer {
+ /// The error it throws.
+ static const ERROR = "I am a bad transformer!";
+
+ /// The list of asset names that it should output.
+ final List<String> outputs;
+
+ BadTransformer(this.outputs);
+
+ Future<bool> doIsPrimary(Asset asset) => new Future.value(true);
+
+ Future doApply(Transform transform) {
+ return newFuture(() {
+ // Create the outputs first.
+ for (var output in outputs) {
+ var id = new AssetId.parse(output);
+ transform.addOutput(new Asset.fromString(id, output));
+ }
+
+ // Then fail.
+ throw ERROR;
+ });
+ }
+}
diff --git a/pkg/barback/test/transformer/check_content.dart b/pkg/barback/test/transformer/check_content.dart
new file mode 100644
index 0000000..252ee1c
--- /dev/null
+++ b/pkg/barback/test/transformer/check_content.dart
@@ -0,0 +1,31 @@
+// Copyright (c) 2013, 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 barback.test.transformer.check_content;
+
+import 'dart:async';
+
+import 'package:barback/barback.dart';
+
+import 'mock.dart';
+
+/// A transformer that modifies assets with the given content.
+class CheckContentTransformer extends MockTransformer {
+ final String content;
+ final String addition;
+
+ CheckContentTransformer(this.content, this.addition);
+
+ Future<bool> doIsPrimary(Asset asset) =>
+ asset.readAsString().then((value) => value == content);
+
+ Future doApply(Transform transform) {
+ return getPrimary(transform).then((primary) {
+ return primary.readAsString().then((value) {
+ transform.addOutput(
+ new Asset.fromString(primary.id, "$value$addition"));
+ });
+ });
+ }
+}
diff --git a/pkg/barback/test/transformer/create_asset.dart b/pkg/barback/test/transformer/create_asset.dart
new file mode 100644
index 0000000..9e89516
--- /dev/null
+++ b/pkg/barback/test/transformer/create_asset.dart
@@ -0,0 +1,28 @@
+// Copyright (c) 2013, 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 barback.test.transformer.create_asset;
+
+import 'dart:async';
+
+import 'package:barback/barback.dart';
+import 'package:barback/src/utils.dart';
+
+import 'mock.dart';
+
+/// A transformer that outputs an asset with the given id.
+class CreateAssetTransformer extends MockTransformer {
+ final String output;
+
+ CreateAssetTransformer(this.output);
+
+ Future<bool> doIsPrimary(Asset asset) => new Future.value(true);
+
+ Future doApply(Transform transform) {
+ return newFuture(() {
+ transform.addOutput(
+ new Asset.fromString(new AssetId.parse(output), output));
+ });
+ }
+}
diff --git a/pkg/barback/test/transformer/many_to_one.dart b/pkg/barback/test/transformer/many_to_one.dart
new file mode 100644
index 0000000..efaf3c47
--- /dev/null
+++ b/pkg/barback/test/transformer/many_to_one.dart
@@ -0,0 +1,46 @@
+// Copyright (c) 2013, 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 barback.test.transformer.many_to_one;
+
+import 'dart:async';
+
+import 'package:barback/barback.dart';
+import 'package:barback/src/utils.dart';
+
+import 'mock.dart';
+
+/// A transformer that uses the contents of a file to define the other inputs.
+///
+/// Outputs a file with the same name as the primary but with an "out"
+/// extension containing the concatenated contents of all non-primary inputs.
+class ManyToOneTransformer extends MockTransformer {
+ final String extension;
+
+ /// Creates a transformer that consumes assets with [extension].
+ ///
+ /// That file contains a comma-separated list of paths and it will input
+ /// files at each of those paths.
+ ManyToOneTransformer(this.extension);
+
+ Future<bool> doIsPrimary(Asset asset) =>
+ new Future.value(asset.id.extension == ".$extension");
+
+ Future doApply(Transform transform) {
+ return getPrimary(transform)
+ .then((primary) => primary.readAsString())
+ .then((contents) {
+ // Get all of the included inputs.
+ return Future.wait(contents.split(",").map((path) {
+ var id = new AssetId(transform.primaryId.package, path);
+ return getInput(transform, id).then((input) => input.readAsString());
+ }));
+ }).then((outputs) {
+ var id = transform.primaryId.changeExtension(".out");
+ transform.addOutput(new Asset.fromString(id, outputs.join()));
+ });
+ }
+
+ String toString() => "many->1 $extension";
+}
diff --git a/pkg/barback/test/transformer/mock.dart b/pkg/barback/test/transformer/mock.dart
new file mode 100644
index 0000000..b831cf7
--- /dev/null
+++ b/pkg/barback/test/transformer/mock.dart
@@ -0,0 +1,134 @@
+// Copyright (c) 2013, 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 barback.test.transformer.mock;
+
+import 'dart:async';
+
+import 'package:barback/barback.dart';
+import 'package:barback/src/utils.dart';
+
+/// The abstract base class for transformers used to test barback.
+///
+/// This adds the ability to pause and resume different components of the
+/// transformers, and to tell whether they're running, when they start running,
+/// and how many times they've run.
+///
+/// Transformers extending this should override [doIsPrimary] and [doApply]
+/// rather than [isPrimary] and [apply], and they should use [getInput] and
+/// [getPrimary] rather than [transform.getInput] and [transform.primaryInput].
+abstract class MockTransformer extends Transformer {
+ /// The number of times the transformer has been applied.
+ int get numRuns => _numRuns;
+ var _numRuns = 0;
+
+ /// The number of currently running transforms.
+ int _runningTransforms = 0;
+
+ // A completer for pausing the transformer before it finishes running [apply].
+ Completer _apply;
+
+ // Completers for pausing the transformer before it finishes running
+ // [isPrimary].
+ final _isPrimary = new Map<AssetId, Completer>();
+
+ // Completers for pausing the transformer before it finishes getting inputs
+ // the [Transform].
+ final _getInput = new Map<AssetId, Completer>();
+
+ /// A future that completes when this transformer begins running.
+ ///
+ /// Once this transformer finishes running, this is reset to a new completer,
+ /// so it can be used multiple times.
+ Future get started => _started.future;
+ var _started = new Completer();
+
+ /// `true` if any transforms are currently running.
+ bool get isRunning => _runningTransforms > 0;
+
+ /// Causes the transformer to pause after running [apply] but before the
+ /// returned Future completes.
+ ///
+ /// This can be resumed by calling [resumeApply].
+ void pauseApply() {
+ _apply = new Completer();
+ }
+
+ /// Resumes the transformer's [apply] call after [pauseApply] was called.
+ void resumeApply() {
+ _apply.complete();
+ _apply = null;
+ }
+
+ /// Causes the transformer to pause after running [isPrimary] on the asset
+ /// with the given [name], but before the returned Future completes.
+ ///
+ /// This can be resumed by calling [resumeIsPrimary].
+ void pauseIsPrimary(String name) {
+ _isPrimary[new AssetId.parse(name)] = new Completer();
+ }
+
+ /// Resumes the transformer's [isPrimary] call on the asset with the given
+ /// [name] after [pauseIsPrimary] was called.
+ void resumeIsPrimary(String name) {
+ _isPrimary.remove(new AssetId.parse(name)).complete();
+ }
+
+ /// Causes the transformer to pause while loading the input with the given
+ /// [name]. This can be the primary input or a secondary input.
+ ///
+ /// This can be resumed by calling [resumeGetInput].
+ void pauseGetInput(String name) {
+ _getInput[new AssetId.parse(name)] = new Completer();
+ }
+
+ /// Resumes the transformer's loading of the input with the given [name] after
+ /// [pauseGetInput] was called.
+ void resumeGetInput(String name) {
+ _getInput.remove(new AssetId.parse(name)).complete();
+ }
+
+ /// Like [Transform.getInput], but respects [pauseGetInput].
+ ///
+ /// This is intended for use by subclasses of [MockTransformer].
+ Future<Asset> getInput(Transform transform, AssetId id) {
+ return newFuture(() {
+ if (_getInput.containsKey(id)) return _getInput[id].future;
+ }).then((_) => transform.getInput(id));
+ }
+
+ /// Like [Transform.primaryInput], but respects [pauseGetInput].
+ ///
+ /// This is intended for use by subclasses of [MockTransformer].
+ Future<Asset> getPrimary(Transform transform) =>
+ getInput(transform, transform.primaryId);
+
+ Future<bool> isPrimary(Asset asset) {
+ return newFuture(() => doIsPrimary(asset)).then((result) {
+ return newFuture(() {
+ if (_isPrimary.containsKey(asset.id)) {
+ return _isPrimary[asset.id].future;
+ }
+ }).then((_) => result);
+ });
+ }
+
+ Future apply(Transform transform) {
+ _numRuns++;
+ if (_runningTransforms == 0) _started.complete();
+ _runningTransforms++;
+ return newFuture(() => doApply(transform)).then((_) {
+ if (_apply != null) return _apply.future;
+ }).whenComplete(() {
+ _runningTransforms--;
+ if (_runningTransforms == 0) _started = new Completer();
+ });
+ }
+
+ /// The wrapped version of [isPrimary] for subclasses to override.
+ Future<bool> doIsPrimary(Asset asset);
+
+ /// The wrapped version of [doApply] for subclasses to override.
+ Future doApply(Transform transform);
+}
diff --git a/pkg/barback/test/transformer/one_to_many.dart b/pkg/barback/test/transformer/one_to_many.dart
new file mode 100644
index 0000000..e9d301d
--- /dev/null
+++ b/pkg/barback/test/transformer/one_to_many.dart
@@ -0,0 +1,39 @@
+// Copyright (c) 2013, 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 barback.test.transformer.one_to_many;
+
+import 'dart:async';
+
+import 'package:barback/barback.dart';
+
+import 'mock.dart';
+
+/// A [Transformer] that takes an input asset that contains a comma-separated
+/// list of paths and outputs a file for each path.
+class OneToManyTransformer extends MockTransformer {
+ final String extension;
+
+ /// Creates a transformer that consumes assets with [extension].
+ ///
+ /// That file contains a comma-separated list of paths and it will output
+ /// files at each of those paths.
+ OneToManyTransformer(this.extension);
+
+ Future<bool> doIsPrimary(Asset asset) =>
+ new Future.value(asset.id.extension == ".$extension");
+
+ Future doApply(Transform transform) {
+ return getPrimary(transform)
+ .then((input) => input.readAsString())
+ .then((lines) {
+ for (var line in lines.split(",")) {
+ var id = new AssetId(transform.primaryId.package, line);
+ transform.addOutput(new Asset.fromString(id, "spread $extension"));
+ }
+ });
+ }
+
+ String toString() => "1->many $extension";
+}
diff --git a/pkg/barback/test/transformer/rewrite.dart b/pkg/barback/test/transformer/rewrite.dart
new file mode 100644
index 0000000..4d3faa88
--- /dev/null
+++ b/pkg/barback/test/transformer/rewrite.dart
@@ -0,0 +1,43 @@
+// Copyright (c) 2013, 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 barback.test.transformer.rewrite;
+
+import 'dart:async';
+
+import 'package:barback/barback.dart';
+
+import 'mock.dart';
+
+/// A [Transformer] that takes assets ending with one extension and generates
+/// assets with a given extension.
+///
+/// Appends the output extension to the contents of the input file.
+class RewriteTransformer extends MockTransformer {
+ final String from;
+ final String to;
+
+ /// Creates a transformer that rewrites assets whose extension is [from] to
+ /// one whose extension is [to].
+ ///
+ /// [to] may be a space-separated list in which case multiple outputs will be
+ /// created for each input.
+ RewriteTransformer(this.from, this.to);
+
+ Future<bool> doIsPrimary(Asset asset) =>
+ new Future.value(asset.id.extension == ".$from");
+
+ Future doApply(Transform transform) {
+ return getPrimary(transform).then((input) {
+ return Future.wait(to.split(" ").map((extension) {
+ var id = transform.primaryId.changeExtension(".$extension");
+ return input.readAsString().then((content) {
+ transform.addOutput(new Asset.fromString(id, "$content.$extension"));
+ });
+ }));
+ });
+ }
+
+ String toString() => "$from->$to";
+}
diff --git a/pkg/barback/test/utils.dart b/pkg/barback/test/utils.dart
index fcda962..ab41a59 100644
--- a/pkg/barback/test/utils.dart
+++ b/pkg/barback/test/utils.dart
@@ -10,6 +10,8 @@
import 'package:barback/barback.dart';
import 'package:barback/src/asset_cascade.dart';
+import 'package:barback/src/asset_set.dart';
+import 'package:barback/src/cancelable_future.dart';
import 'package:barback/src/package_graph.dart';
import 'package:barback/src/utils.dart';
import 'package:path/path.dart' as pathos;
@@ -17,6 +19,14 @@
import 'package:stack_trace/stack_trace.dart';
import 'package:unittest/compact_vm_config.dart';
+export 'transformer/bad.dart';
+export 'transformer/check_content.dart';
+export 'transformer/create_asset.dart';
+export 'transformer/many_to_one.dart';
+export 'transformer/mock.dart';
+export 'transformer/one_to_many.dart';
+export 'transformer/rewrite.dart';
+
var _configured = false;
MockProvider _provider;
@@ -96,6 +106,16 @@
}, "modify asset $name");
}
+/// Schedules an error to be generated when loading the asset identified by
+/// [name].
+///
+/// Does not update the asset in the graph.
+void setAssetError(String name) {
+ schedule(() {
+ _provider._setAssetError(name);
+ }, "set error for asset $name");
+}
+
/// Schedules a pause of the internally created [PackageProvider].
///
/// All asset requests that the [PackageGraph] makes to the provider after this
@@ -117,31 +137,16 @@
/// [buildShouldFail], so those can be used to validate build results before and
/// after this.
void buildShouldNotBeDone() {
- var resultAllowed = false;
- var trace = new Trace.current();
- _graph.results.elementAt(_nextBuildResult).then((result) {
- if (resultAllowed) return;
-
- currentSchedule.signalError(
- new Exception("Expected build not to terminate "
- "here, but it terminated with result: $result"), trace);
- }).catchError((error) {
- if (resultAllowed) return;
- currentSchedule.signalError(error);
- });
-
- schedule(() {
- // Pump the event queue in case the build completes out-of-band after we get
- // here. If it does, we want to signal an error.
- return pumpEventQueue().then((_) {
- resultAllowed = true;
- });
- }, "ensuring build doesn't terminate");
+ _futureShouldNotCompleteUntil(
+ _graph.results.elementAt(_nextBuildResult),
+ schedule(() => pumpEventQueue(), "build should not terminate"),
+ "build");
}
/// Expects that the next [BuildResult] is a build success.
void buildShouldSucceed() {
expect(_getNextBuildResult().then((result) {
+ result.errors.forEach(currentSchedule.signalError);
expect(result.succeeded, isTrue);
}), completes);
}
@@ -190,9 +195,8 @@
schedule(() {
return _graph.getAssetById(id).then((asset) {
// TODO(rnystrom): Make an actual Matcher class for this.
- expect(asset, new isInstanceOf<MockAsset>());
expect(asset.id, equals(id));
- expect(asset.contents, equals(contents));
+ expect(asset.readAsString(), completion(equals(contents)));
});
}, "get asset $name");
}
@@ -213,12 +217,25 @@
}, "get asset $name");
}
+/// Schedules an expectation that a [getAssetById] call for the given asset
+/// won't terminate at this point in the schedule.
+void expectAssetDoesNotComplete(String name) {
+ var id = new AssetId.parse(name);
+
+ schedule(() {
+ return _futureShouldNotCompleteUntil(
+ _graph.getAssetById(id),
+ pumpEventQueue(),
+ "asset $id");
+ }, "asset $id should not complete");
+}
+
/// Returns a matcher for an [AssetNotFoundException] with the given [id].
Matcher isAssetNotFoundException(String name) {
var id = new AssetId.parse(name);
return allOf(
new isInstanceOf<AssetNotFoundException>(),
- predicate((error) => error.id == id, 'id is $name'));
+ predicate((error) => error.id == id, 'id == $name'));
}
/// Returns a matcher for an [AssetCollisionException] with the given [id].
@@ -226,7 +243,7 @@
var id = new AssetId.parse(name);
return allOf(
new isInstanceOf<AssetCollisionException>(),
- predicate((error) => error.id == id, 'id is $name'));
+ predicate((error) => error.id == id, 'id == $name'));
}
/// Returns a matcher for a [MissingInputException] with the given [id].
@@ -234,7 +251,7 @@
var id = new AssetId.parse(name);
return allOf(
new isInstanceOf<MissingInputException>(),
- predicate((error) => error.id == id, 'id is $name'));
+ predicate((error) => error.id == id, 'id == $name'));
}
/// Returns a matcher for an [InvalidOutputException] with the given id and
@@ -244,7 +261,37 @@
return allOf(
new isInstanceOf<InvalidOutputException>(),
predicate((error) => error.package == package, 'package is $package'),
- predicate((error) => error.id == id, 'id is $name'));
+ predicate((error) => error.id == id, 'id == $name'));
+}
+
+/// Returns a matcher for a [MockLoadException] with the given [id].
+Matcher isMockLoadException(String name) {
+ var id = new AssetId.parse(name);
+ return allOf(
+ new isInstanceOf<MockLoadException>(),
+ predicate((error) => error.id == id, 'id == $name'));
+}
+
+/// Asserts that [future] shouldn't complete until after [delay] completes.
+///
+/// Once [delay] completes, the output of [future] is ignored, even if it's an
+/// error.
+///
+/// [description] should describe [future].
+Future _futureShouldNotCompleteUntil(Future future, Future delay,
+ String description) {
+ var trace = new Trace.current();
+ var cancelable = new CancelableFuture(future);
+ cancelable.then((result) {
+ currentSchedule.signalError(
+ new Exception("Expected $description not to complete here, but it "
+ "completed with result: $result"),
+ trace);
+ }).catchError((error) {
+ currentSchedule.signalError(error);
+ });
+
+ return delay.then((_) => cancelable.cancel());
}
/// An [AssetProvider] that provides the given set of assets.
@@ -253,6 +300,10 @@
Map<String, _MockPackage> _packages;
+ /// The set of assets for which [MockLoadException]s should be emitted if
+ /// they're loaded.
+ final _errors = new Set<AssetId>();
+
/// The completer that [getAsset()] is waiting on to complete when paused.
///
/// If `null` it will return the asset immediately.
@@ -277,13 +328,13 @@
if (assets is Map) {
assetList = assets.keys.map((asset) {
var id = new AssetId.parse(asset);
- return new MockAsset(id, assets[asset]);
+ return new _MockAsset(id, assets[asset]);
});
} else if (assets is Iterable) {
assetList = assets.map((asset) {
var id = new AssetId.parse(asset);
var contents = pathos.basenameWithoutExtension(id.path);
- return new MockAsset(id, contents);
+ return new _MockAsset(id, contents);
});
}
@@ -291,21 +342,26 @@
(package, assets) {
var packageTransformers = transformers[package];
if (packageTransformers == null) packageTransformers = [];
- return new _MockPackage(assets, packageTransformers.toList());
+ return new _MockPackage(
+ new AssetSet.from(assets), packageTransformers.toList());
});
// If there are no assets or transformers, add a dummy package. This better
// simulates the real world, where there'll always be at least the
// entrypoint package.
- if (_packages.isEmpty) _packages = {"app": new _MockPackage([], [])};
+ if (_packages.isEmpty) {
+ _packages = {"app": new _MockPackage(new AssetSet(), [])};
+ }
}
void _modifyAsset(String name, String contents) {
var id = new AssetId.parse(name);
- var asset = _packages[id.package].assets.firstWhere((a) => a.id == id);
- asset.contents = contents;
+ _errors.remove(id);
+ _packages[id.package].assets[id].contents = contents;
}
+ void _setAssetError(String name) => _errors.add(new AssetId.parse(name));
+
List<AssetId> listAssets(String package, {String within}) {
if (within != null) {
throw new UnimplementedError("Doesn't handle 'within' yet.");
@@ -323,6 +379,14 @@
}
Future<Asset> getAsset(AssetId id) {
+ // Eagerly load the asset so we can test an asset's value changing between
+ // when a load starts and when it finishes.
+ var package = _packages[id.package];
+ var asset;
+ if (package != null) asset = package.assets[id];
+
+ var hasError = _errors.contains(id);
+
var future;
if (_pauseCompleter != null) {
future = _pauseCompleter.future;
@@ -331,225 +395,38 @@
}
return future.then((_) {
- var package = _packages[id.package];
- if (package == null) throw new AssetNotFoundException(id);
-
- return package.assets.firstWhere((asset) => asset.id == id,
- orElse: () => throw new AssetNotFoundException(id));
+ if (hasError) throw new MockLoadException(id);
+ if (asset == null) throw new AssetNotFoundException(id);
+ return asset;
});
}
}
+/// Error thrown for assets with [setAssetError] set.
+class MockLoadException implements Exception {
+ final AssetId id;
+
+ MockLoadException(this.id);
+
+ String toString() => "Error loading $id.";
+}
+
/// Used by [MockProvider] to keep track of which assets and transformers exist
/// for each package.
class _MockPackage {
- final List<MockAsset> assets;
+ final AssetSet assets;
final List<List<Transformer>> transformers;
_MockPackage(this.assets, Iterable<Iterable<Transformer>> transformers)
: transformers = transformers.map((phase) => phase.toList()).toList();
}
-/// A [Transformer] that takes assets ending with one extension and generates
-/// assets with a given extension.
-///
-/// Appends the output extension to the contents of the input file.
-class RewriteTransformer extends Transformer {
- final String from;
- final String to;
-
- /// The number of times the transformer has been applied.
- int numRuns = 0;
-
- /// The number of currently running transforms.
- int _runningTransforms = 0;
-
- /// The completer that the transform is waiting on to complete.
- ///
- /// If `null` the transform will complete immediately.
- Completer _wait;
-
- /// A future that completes when the first apply of this transformer begins.
- Future get started => _started.future;
- final _started = new Completer();
-
- /// Creates a transformer that rewrites assets whose extension is [from] to
- /// one whose extension is [to].
- ///
- /// [to] may be a space-separated list in which case multiple outputs will be
- /// created for each input.
- RewriteTransformer(this.from, this.to);
-
- /// `true` if any transforms are currently running.
- bool get isRunning => _runningTransforms > 0;
-
- /// Tells the transform to wait during its transformation until [complete()]
- /// is called.
- ///
- /// Lets you test the asynchronous behavior of transformers.
- void wait() {
- _wait = new Completer();
- }
-
- void complete() {
- _wait.complete();
- _wait = null;
- }
-
- Future<bool> isPrimary(Asset asset) {
- return new Future.value(asset.id.extension == ".$from");
- }
-
- Future apply(Transform transform) {
- numRuns++;
- if (!_started.isCompleted) _started.complete();
- _runningTransforms++;
- return transform.primaryInput.then((input) {
- return Future.wait(to.split(" ").map((extension) {
- var id = transform.primaryId.changeExtension(".$extension");
- return input.readAsString().then((content) {
- transform.addOutput(new MockAsset(id, "$content.$extension"));
- });
- })).then((_) {
- if (_wait != null) return _wait.future;
- });
- }).whenComplete(() {
- _runningTransforms--;
- });
- }
-
- String toString() => "$from->$to";
-}
-
-/// A [Transformer] that takes an input asset that contains a comma-separated
-/// list of paths and outputs a file for each path.
-class OneToManyTransformer extends Transformer {
- final String extension;
-
- /// The number of times the transformer has been applied.
- int numRuns = 0;
-
- /// Creates a transformer that consumes assets with [extension].
- ///
- /// That file contains a comma-separated list of paths and it will output
- /// files at each of those paths.
- OneToManyTransformer(this.extension);
-
- Future<bool> isPrimary(Asset asset) {
- return new Future.value(asset.id.extension == ".$extension");
- }
-
- Future apply(Transform transform) {
- numRuns++;
- return transform.primaryInput.then((input) {
- return input.readAsString().then((lines) {
- for (var line in lines.split(",")) {
- var id = new AssetId(transform.primaryId.package, line);
- transform.addOutput(new MockAsset(id, "spread $extension"));
- }
- });
- });
- }
-
- String toString() => "1->many $extension";
-}
-
-/// A transformer that uses the contents of a file to define the other inputs.
-///
-/// Outputs a file with the same name as the primary but with an "out"
-/// extension containing the concatenated contents of all non-primary inputs.
-class ManyToOneTransformer extends Transformer {
- final String extension;
-
- /// The number of times the transformer has been applied.
- int numRuns = 0;
-
- /// Creates a transformer that consumes assets with [extension].
- ///
- /// That file contains a comma-separated list of paths and it will input
- /// files at each of those paths.
- ManyToOneTransformer(this.extension);
-
- Future<bool> isPrimary(Asset asset) {
- return new Future.value(asset.id.extension == ".$extension");
- }
-
- Future apply(Transform transform) {
- numRuns++;
- return transform.primaryInput.then((primary) {
- return primary.readAsString().then((contents) {
- // Get all of the included inputs.
- var inputs = contents.split(",").map((path) {
- var id = new AssetId(transform.primaryId.package, path);
- return transform.getInput(id);
- });
-
- return Future.wait(inputs);
- }).then((inputs) {
- // Concatenate them to one output.
- var output = "";
- return Future.forEach(inputs, (input) {
- return input.readAsString().then((contents) {
- output += contents;
- });
- }).then((_) {
- var id = transform.primaryId.changeExtension(".out");
- transform.addOutput(new MockAsset(id, output));
- });
- });
- });
- }
-
- String toString() => "many->1 $extension";
-}
-
-/// A transformer that throws an exception when run, after generating the
-/// given outputs.
-class BadTransformer extends Transformer {
- /// The error it throws.
- static const ERROR = "I am a bad transformer!";
-
- /// The list of asset names that it should output.
- final List<String> outputs;
-
- BadTransformer(this.outputs);
-
- Future<bool> isPrimary(Asset asset) => new Future.value(true);
- Future apply(Transform transform) {
- return newFuture(() {
- // Create the outputs first.
- for (var output in outputs) {
- var id = new AssetId.parse(output);
- transform.addOutput(new MockAsset(id, output));
- }
-
- // Then fail.
- throw ERROR;
- });
- }
-}
-
-/// A transformer that outputs an asset with the given id.
-class CreateAssetTransformer extends Transformer {
- final String output;
-
- CreateAssetTransformer(this.output);
-
- Future<bool> isPrimary(Asset asset) => new Future.value(true);
-
- Future apply(Transform transform) {
- return newFuture(() {
- transform.addOutput(new MockAsset(new AssetId.parse(output), output));
- });
- }
-}
-
/// An implementation of [Asset] that never hits the file system.
-class MockAsset implements Asset {
+class _MockAsset implements Asset {
final AssetId id;
String contents;
- MockAsset(this.id, this.contents);
+ _MockAsset(this.id, this.contents);
Future<String> readAsString({Encoding encoding}) =>
new Future.value(contents);
@@ -557,4 +434,4 @@
Stream<List<int>> read() => throw new UnimplementedError();
String toString() => "MockAsset $id $contents";
-}
\ No newline at end of file
+}
diff --git a/pkg/custom_element/lib/custom_element.dart b/pkg/custom_element/lib/custom_element.dart
new file mode 100644
index 0000000..369501c
--- /dev/null
+++ b/pkg/custom_element/lib/custom_element.dart
@@ -0,0 +1,705 @@
+// Copyright (c) 2013, 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.
+
+/**
+ * Custom Elements let authors define their own elements. Authors associate code
+ * with custom tag names, and then use those custom tag names as they would any
+ * standard tag. See <www.polymer-project.org/platform/custom-elements.html>
+ * for more information.
+ */
+library custom_element;
+
+import 'dart:async';
+import 'dart:html';
+import 'package:mdv/mdv.dart' as mdv;
+import 'package:meta/meta.dart';
+import 'src/custom_tag_name.dart';
+
+// TODO(jmesserly): replace with a real custom element polyfill.
+// This is just something temporary.
+/**
+ * *Warning*: this implementation is a work in progress. It only implements
+ * the specification partially.
+ *
+ * Registers a custom HTML element with [localName] and the associated
+ * constructor. This will ensure the element is detected and
+ *
+ * See the specification at:
+ * <https://dvcs.w3.org/hg/webcomponents/raw-file/tip/spec/custom/index.html>
+ */
+void registerCustomElement(String localName, CustomElement create()) {
+ if (_customElements == null) {
+ _customElements = {};
+ CustomElement.templateCreated.add(initCustomElements);
+ // TODO(jmesserly): use MutationObserver to watch for inserts?
+ }
+
+ if (!isCustomTag(localName)) {
+ throw new ArgumentError('$localName is not a valid custom element name, '
+ 'it should have at least one dash and not be a reserved name.');
+ }
+
+ if (_customElements.containsKey(localName)) {
+ throw new ArgumentError('custom element $localName already registered.');
+ }
+
+ // TODO(jmesserly): validate this is a valid tag name, not a selector.
+ _customElements[localName] = create;
+
+ // Initialize elements already on the page.
+ for (var query in [localName, '[is=$localName]']) {
+ for (var element in document.queryAll(query)) {
+ _initCustomElement(element, create);
+ }
+ }
+}
+
+/**
+ * Creates a new element and returns it. If the [localName] has been registered
+ * with [registerCustomElement], it will create the custom element.
+ *
+ * This is similar to `new Element.tag` in Dart and `document.createElement`
+ * in JavaScript.
+ *
+ * *Warning*: this API is temporary until [dart:html] supports custom elements.
+ */
+Element createElement(String localName) =>
+ initCustomElements(new Element.tag(localName));
+
+/**
+ * Similar to `new Element.html`, but automatically creates registed custom
+ * elements.
+ * *Warning*: this API is temporary until [dart:html] supports custom elements.
+ */
+Element createElementFromHtml(String html) =>
+ initCustomElements(new Element.html(html));
+
+/**
+ * Initialize any registered custom elements recursively in the [node] tree.
+ * For convenience this returns the [node] instance.
+ *
+ * *Warning*: this API is temporary until [dart:html] supports custom elements.
+ */
+Node initCustomElements(Node node) {
+ for (var c = node.firstChild; c != null; c = c.nextNode) {
+ initCustomElements(c);
+ }
+ if (node is Element) {
+ var ctor = _customElements[node.localName];
+ if (ctor == null) {
+ var attr = node.attributes['is'];
+ if (attr != null) ctor = _customElements[attr];
+ }
+ if (ctor != null) _initCustomElement(node, ctor);
+ }
+ return node;
+}
+
+/**
+ * The base class for all Dart web components. In addition to the [Element]
+ * interface, it also provides lifecycle methods:
+ * - [created]
+ * - [inserted]
+ * - [attributeChanged]
+ * - [removed]
+ */
+class CustomElement implements Element {
+ /** The web component element wrapped by this class. */
+ Element _host;
+ List _shadowRoots;
+
+ /**
+ * Shadow roots generated by dwc for each custom element, indexed by the
+ * custom element tag name.
+ */
+ Map<String, dynamic> _generatedRoots = {};
+
+ /**
+ * Temporary property until components extend [Element]. An element can
+ * only be associated with one host, and it is an error to use a web component
+ * without an associated host element.
+ */
+ Element get host {
+ if (_host == null) throw new StateError('host element has not been set.');
+ return _host;
+ }
+
+ set host(Element value) {
+ if (value == null) {
+ throw new ArgumentError('host must not be null.');
+ }
+ // TODO(jmesserly): xtag used to return "null" if unset, now it checks for
+ // "this". Temporarily allow both.
+ var xtag = value.xtag;
+ if (xtag != null && xtag != value) {
+ throw new ArgumentError('host must not have its xtag property set.');
+ }
+ if (_host != null) {
+ throw new StateError('host can only be set once.');
+ }
+
+ value.xtag = this;
+ _host = value;
+ }
+
+ /**
+ * **Note**: This is an implementation helper and should not need to be called
+ * from your code.
+ *
+ * Creates the [ShadowRoot] backing this component.
+ */
+ createShadowRoot([String componentName]) {
+ var root = host.createShadowRoot();
+ if (componentName != null) {
+ _generatedRoots[componentName] = root;
+ }
+ return root;
+ }
+
+ getShadowRoot(String componentName) => _generatedRoots[componentName];
+
+
+ /**
+ * *Warning*: This is an implementation helper for Custom Elements and
+ * should not be used in your code.
+ *
+ * Clones the template, instantiates custom elements and hooks events, then
+ * returns it.
+ */
+ DocumentFragment cloneTemplate(DocumentFragment shadowTemplate) {
+ var result = shadowTemplate.clone(true);
+ // TODO(jmesserly): should bindModel ensure this happens?
+ TemplateElement.bootstrap(result);
+ if (_templateCreated != null) {
+ for (var callback in _templateCreated) callback(result);
+ }
+ return result;
+ }
+
+ // TODO(jmesserly): ideally this would be a stream, but they don't allow
+ // reentrancy.
+ static Set<DocumentFragmentCreated> _templateCreated;
+
+ /**
+ * *Warning*: This is an implementation helper for Custom Elements and
+ * should not be used in your code.
+ *
+ * This event is fired whenever a template is instantiated via
+ * [cloneTemplate] or via [Element.createInstance]
+ */
+ // TODO(jmesserly): This is a hack, and is neccesary for the polyfill
+ // because custom elements are not upgraded during clone()
+ static Set<DocumentFragmentCreated> get templateCreated {
+ if (_templateCreated == null) {
+ _templateCreated = new Set<DocumentFragmentCreated>();
+ mdv.instanceCreated.listen((value) {
+ for (var callback in _templateCreated) callback(value);
+ });
+ }
+ return _templateCreated;
+ }
+ /**
+ * Invoked when this component gets created.
+ * Note that [root] will be a [ShadowRoot] if the browser supports Shadow DOM.
+ */
+ void created() {}
+
+ /** Invoked when this component gets inserted in the DOM tree. */
+ void inserted() {}
+
+ /** Invoked when this component is removed from the DOM tree. */
+ void removed() {}
+
+ // TODO(jmesserly): how do we implement this efficiently?
+ // See https://github.com/dart-lang/web-ui/issues/37
+ /** Invoked when any attribute of the component is modified. */
+ void attributeChanged(String name, String oldValue, String newValue) {}
+
+ get model => host.model;
+
+ void set model(newModel) {
+ host.model = newModel;
+ }
+
+ get templateInstance => host.templateInstance;
+ get isTemplate => host.isTemplate;
+ get ref => host.ref;
+ get content => host.content;
+ DocumentFragment createInstance(model, [BindingDelegate delegate]) =>
+ host.createInstance(model, delegate);
+ createBinding(String name, model, String path) =>
+ host.createBinding(name, model, path);
+ void bind(String name, model, String path) => host.bind(name, model, path);
+ void unbind(String name) => host.unbind(name);
+ void unbindAll() => host.unbindAll();
+ get bindings => host.bindings;
+ BindingDelegate get bindingDelegate => host.bindingDelegate;
+ set bindingDelegate(BindingDelegate value) { host.bindingDelegate = value; }
+
+ // TODO(jmesserly): this forwarding is temporary until Dart supports
+ // subclassing Elements.
+ // TODO(jmesserly): we were missing the setter for title, are other things
+ // missing setters?
+
+ List<Node> get nodes => host.nodes;
+
+ set nodes(Iterable<Node> value) { host.nodes = value; }
+
+ /**
+ * Replaces this node with another node.
+ */
+ Node replaceWith(Node otherNode) { host.replaceWith(otherNode); }
+
+ /**
+ * Removes this node from the DOM.
+ */
+ void remove() => host.remove();
+
+ Node get nextNode => host.nextNode;
+
+ String get nodeName => host.nodeName;
+
+ Document get document => host.document;
+
+ Node get previousNode => host.previousNode;
+
+ String get text => host.text;
+
+ set text(String v) { host.text = v; }
+
+ bool contains(Node other) => host.contains(other);
+
+ bool hasChildNodes() => host.hasChildNodes();
+
+ Node insertBefore(Node newChild, Node refChild) =>
+ host.insertBefore(newChild, refChild);
+
+ Node insertAllBefore(Iterable<Node> newChild, Node refChild) =>
+ host.insertAllBefore(newChild, refChild);
+
+ Map<String, String> get attributes => host.attributes;
+ set attributes(Map<String, String> value) {
+ host.attributes = value;
+ }
+
+ List<Element> get elements => host.children;
+
+ set elements(List<Element> value) {
+ host.children = value;
+ }
+
+ List<Element> get children => host.children;
+
+ set children(List<Element> value) {
+ host.children = value;
+ }
+
+ Set<String> get classes => host.classes;
+
+ set classes(Iterable<String> value) {
+ host.classes = value;
+ }
+
+ CssRect get contentEdge => host.contentEdge;
+ CssRect get paddingEdge => host.paddingEdge;
+ CssRect get borderEdge => host.borderEdge;
+ CssRect get marginEdge => host.marginEdge;
+ Point get documentOffset => host.documentOffset;
+ Point offsetTo(Element parent) => host.offsetTo(parent);
+
+ Map<String, String> getNamespacedAttributes(String namespace) =>
+ host.getNamespacedAttributes(namespace);
+
+ CssStyleDeclaration getComputedStyle([String pseudoElement])
+ => host.getComputedStyle(pseudoElement);
+
+ Element clone(bool deep) => host.clone(deep);
+
+ Element get parent => host.parent;
+
+ Node get parentNode => host.parentNode;
+
+ String get nodeValue => host.nodeValue;
+
+ @deprecated
+ // TODO(sigmund): restore the old return type and call host.on when
+ // dartbug.com/8131 is fixed.
+ dynamic get on { throw new UnsupportedError('on is deprecated'); }
+
+ String get contentEditable => host.contentEditable;
+ set contentEditable(String v) { host.contentEditable = v; }
+
+ String get dir => host.dir;
+ set dir(String v) { host.dir = v; }
+
+ bool get draggable => host.draggable;
+ set draggable(bool v) { host.draggable = v; }
+
+ bool get hidden => host.hidden;
+ set hidden(bool v) { host.hidden = v; }
+
+ String get id => host.id;
+ set id(String v) { host.id = v; }
+
+ String get innerHTML => host.innerHtml;
+
+ void set innerHTML(String v) {
+ host.innerHtml = v;
+ }
+
+ String get innerHtml => host.innerHtml;
+ void set innerHtml(String v) {
+ host.innerHtml = v;
+ }
+
+ bool get isContentEditable => host.isContentEditable;
+
+ String get lang => host.lang;
+ set lang(String v) { host.lang = v; }
+
+ String get outerHtml => host.outerHtml;
+
+ bool get spellcheck => host.spellcheck;
+ set spellcheck(bool v) { host.spellcheck = v; }
+
+ int get tabIndex => host.tabIndex;
+ set tabIndex(int i) { host.tabIndex = i; }
+
+ String get title => host.title;
+
+ set title(String value) { host.title = value; }
+
+ bool get translate => host.translate;
+ set translate(bool v) { host.translate = v; }
+
+ String get dropzone => host.dropzone;
+ set dropzone(String v) { host.dropzone = v; }
+
+ void click() { host.click(); }
+
+ InputMethodContext getInputContext() => host.getInputContext();
+
+ Element insertAdjacentElement(String where, Element element) =>
+ host.insertAdjacentElement(where, element);
+
+ void insertAdjacentHtml(String where, String html) {
+ host.insertAdjacentHtml(where, html);
+ }
+
+ void insertAdjacentText(String where, String text) {
+ host.insertAdjacentText(where, text);
+ }
+
+ Map<String, String> get dataset => host.dataset;
+
+ set dataset(Map<String, String> value) {
+ host.dataset = value;
+ }
+
+ Element get nextElementSibling => host.nextElementSibling;
+
+ Element get offsetParent => host.offsetParent;
+
+ Element get previousElementSibling => host.previousElementSibling;
+
+ CssStyleDeclaration get style => host.style;
+
+ String get tagName => host.tagName;
+
+ String get pseudo => host.pseudo;
+
+ void set pseudo(String value) {
+ host.pseudo = value;
+ }
+
+ // Note: we are not polyfilling the shadow root here. This will be fixed when
+ // we migrate to the JS Shadow DOM polyfills. You can still use getShadowRoot
+ // to retrieve a node that behaves as the shadow root when Shadow DOM is not
+ // enabled.
+ ShadowRoot get shadowRoot => host.shadowRoot;
+
+ void blur() { host.blur(); }
+
+ void focus() { host.focus(); }
+
+ void scrollByLines(int lines) {
+ host.scrollByLines(lines);
+ }
+
+ void scrollByPages(int pages) {
+ host.scrollByPages(pages);
+ }
+
+ void scrollIntoView([ScrollAlignment alignment]) {
+ host.scrollIntoView(alignment);
+ }
+
+ bool matches(String selectors) => host.matches(selectors);
+
+ @deprecated
+ void requestFullScreen(int flags) { requestFullscreen(); }
+
+ void requestFullscreen() { host.requestFullscreen(); }
+
+ void requestPointerLock() { host.requestPointerLock(); }
+
+ Element query(String selectors) => host.query(selectors);
+
+ ElementList queryAll(String selectors) => host.queryAll(selectors);
+
+ HtmlCollection get $dom_children => host.$dom_children;
+
+ int get $dom_childElementCount => host.$dom_childElementCount;
+
+ String get className => host.className;
+ set className(String value) { host.className = value; }
+
+ @deprecated
+ int get clientHeight => client.height;
+
+ @deprecated
+ int get clientLeft => client.left;
+
+ @deprecated
+ int get clientTop => client.top;
+
+ @deprecated
+ int get clientWidth => client.width;
+
+ Rect get client => host.client;
+
+ Element get $dom_firstElementChild => host.$dom_firstElementChild;
+
+ Element get $dom_lastElementChild => host.$dom_lastElementChild;
+
+ @deprecated
+ int get offsetHeight => offset.height;
+
+ @deprecated
+ int get offsetLeft => offset.left;
+
+ @deprecated
+ int get offsetTop => offset.top;
+
+ @deprecated
+ int get offsetWidth => offset.width;
+
+ Rect get offset => host.offset;
+
+ int get scrollHeight => host.scrollHeight;
+
+ int get scrollLeft => host.scrollLeft;
+
+ int get scrollTop => host.scrollTop;
+
+ set scrollLeft(int value) { host.scrollLeft = value; }
+
+ set scrollTop(int value) { host.scrollTop = value; }
+
+ int get scrollWidth => host.scrollWidth;
+
+ String $dom_getAttribute(String name) =>
+ host.$dom_getAttribute(name);
+
+ String $dom_getAttributeNS(String namespaceUri, String localName) =>
+ host.$dom_getAttributeNS(namespaceUri, localName);
+
+ String $dom_setAttributeNS(
+ String namespaceUri, String localName, String value) {
+ host.$dom_setAttributeNS(namespaceUri, localName, value);
+ }
+
+ bool $dom_hasAttributeNS(String namespaceUri, String localName) =>
+ host.$dom_hasAttributeNS(namespaceUri, localName);
+
+ void $dom_removeAttributeNS(String namespaceUri, String localName) =>
+ host.$dom_removeAttributeNS(namespaceUri, localName);
+
+ Rect getBoundingClientRect() => host.getBoundingClientRect();
+
+ List<Rect> getClientRects() => host.getClientRects();
+
+ List<Node> getElementsByClassName(String name) =>
+ host.getElementsByClassName(name);
+
+ List<Node> $dom_getElementsByTagName(String name) =>
+ host.$dom_getElementsByTagName(name);
+
+ bool $dom_hasAttribute(String name) =>
+ host.$dom_hasAttribute(name);
+
+ List<Node> $dom_querySelectorAll(String selectors) =>
+ host.$dom_querySelectorAll(selectors);
+
+ void $dom_removeAttribute(String name) =>
+ host.$dom_removeAttribute(name);
+
+ void $dom_setAttribute(String name, String value) =>
+ host.$dom_setAttribute(name, value);
+
+ get $dom_attributes => host.$dom_attributes;
+
+ List<Node> get $dom_childNodes => host.$dom_childNodes;
+
+ Node get firstChild => host.firstChild;
+
+ Node get lastChild => host.lastChild;
+
+ String get localName => host.localName;
+ String get $dom_localName => host.$dom_localName;
+
+ String get namespaceUri => host.namespaceUri;
+ String get $dom_namespaceUri => host.$dom_namespaceUri;
+
+ int get nodeType => host.nodeType;
+
+ void $dom_addEventListener(String type, EventListener listener,
+ [bool useCapture]) {
+ host.$dom_addEventListener(type, listener, useCapture);
+ }
+
+ bool dispatchEvent(Event event) => host.dispatchEvent(event);
+
+ Node $dom_removeChild(Node oldChild) => host.$dom_removeChild(oldChild);
+
+ void $dom_removeEventListener(String type, EventListener listener,
+ [bool useCapture]) {
+ host.$dom_removeEventListener(type, listener, useCapture);
+ }
+
+ Node $dom_replaceChild(Node newChild, Node oldChild) =>
+ host.$dom_replaceChild(newChild, oldChild);
+
+ get xtag => host.xtag;
+
+ set xtag(value) { host.xtag = value; }
+
+ Node append(Node e) => host.append(e);
+
+ void appendText(String text) => host.appendText(text);
+
+ void appendHtml(String html) => host.appendHtml(html);
+
+ void $dom_scrollIntoView([bool alignWithTop]) {
+ if (alignWithTop == null) {
+ host.$dom_scrollIntoView();
+ } else {
+ host.$dom_scrollIntoView(alignWithTop);
+ }
+ }
+
+ void $dom_scrollIntoViewIfNeeded([bool centerIfNeeded]) {
+ if (centerIfNeeded == null) {
+ host.$dom_scrollIntoViewIfNeeded();
+ } else {
+ host.$dom_scrollIntoViewIfNeeded(centerIfNeeded);
+ }
+ }
+
+ String get regionOverset => host.regionOverset;
+
+ List<Range> getRegionFlowRanges() => host.getRegionFlowRanges();
+
+ // TODO(jmesserly): rename "created" to "onCreated".
+ void onCreated() => created();
+
+ Stream<Event> get onAbort => host.onAbort;
+ Stream<Event> get onBeforeCopy => host.onBeforeCopy;
+ Stream<Event> get onBeforeCut => host.onBeforeCut;
+ Stream<Event> get onBeforePaste => host.onBeforePaste;
+ Stream<Event> get onBlur => host.onBlur;
+ Stream<Event> get onChange => host.onChange;
+ Stream<MouseEvent> get onClick => host.onClick;
+ Stream<MouseEvent> get onContextMenu => host.onContextMenu;
+ Stream<Event> get onCopy => host.onCopy;
+ Stream<Event> get onCut => host.onCut;
+ Stream<Event> get onDoubleClick => host.onDoubleClick;
+ Stream<MouseEvent> get onDrag => host.onDrag;
+ Stream<MouseEvent> get onDragEnd => host.onDragEnd;
+ Stream<MouseEvent> get onDragEnter => host.onDragEnter;
+ Stream<MouseEvent> get onDragLeave => host.onDragLeave;
+ Stream<MouseEvent> get onDragOver => host.onDragOver;
+ Stream<MouseEvent> get onDragStart => host.onDragStart;
+ Stream<MouseEvent> get onDrop => host.onDrop;
+ Stream<Event> get onError => host.onError;
+ Stream<Event> get onFocus => host.onFocus;
+ Stream<Event> get onInput => host.onInput;
+ Stream<Event> get onInvalid => host.onInvalid;
+ Stream<KeyboardEvent> get onKeyDown => host.onKeyDown;
+ Stream<KeyboardEvent> get onKeyPress => host.onKeyPress;
+ Stream<KeyboardEvent> get onKeyUp => host.onKeyUp;
+ Stream<Event> get onLoad => host.onLoad;
+ Stream<MouseEvent> get onMouseDown => host.onMouseDown;
+ Stream<MouseEvent> get onMouseMove => host.onMouseMove;
+ Stream<Event> get onFullscreenChange => host.onFullscreenChange;
+ Stream<Event> get onFullscreenError => host.onFullscreenError;
+ Stream<Event> get onPaste => host.onPaste;
+ Stream<Event> get onReset => host.onReset;
+ Stream<Event> get onScroll => host.onScroll;
+ Stream<Event> get onSearch => host.onSearch;
+ Stream<Event> get onSelect => host.onSelect;
+ Stream<Event> get onSelectStart => host.onSelectStart;
+ Stream<Event> get onSubmit => host.onSubmit;
+ Stream<MouseEvent> get onMouseOut => host.onMouseOut;
+ Stream<MouseEvent> get onMouseOver => host.onMouseOver;
+ Stream<MouseEvent> get onMouseUp => host.onMouseUp;
+ Stream<TouchEvent> get onTouchCancel => host.onTouchCancel;
+ Stream<TouchEvent> get onTouchEnd => host.onTouchEnd;
+ Stream<TouchEvent> get onTouchEnter => host.onTouchEnter;
+ Stream<TouchEvent> get onTouchLeave => host.onTouchLeave;
+ Stream<TouchEvent> get onTouchMove => host.onTouchMove;
+ Stream<TouchEvent> get onTouchStart => host.onTouchStart;
+ Stream<TransitionEvent> get onTransitionEnd => host.onTransitionEnd;
+
+ // TODO(sigmund): do the normal forwarding when dartbug.com/7919 is fixed.
+ Stream<WheelEvent> get onMouseWheel {
+ throw new UnsupportedError('onMouseWheel is not supported');
+ }
+}
+
+
+typedef DocumentFragmentCreated(DocumentFragment fragment);
+
+Map<String, Function> _customElements;
+
+void _initCustomElement(Element node, CustomElement ctor()) {
+ CustomElement element = ctor();
+ element.host = node;
+
+ // TODO(jmesserly): replace lifecycle stuff with a proper polyfill.
+ element.created();
+
+ _registerLifecycleInsert(element);
+}
+
+void _registerLifecycleInsert(CustomElement element) {
+ runAsync(() {
+ // TODO(jmesserly): bottom up or top down insert?
+ var node = element.host;
+
+ // TODO(jmesserly): need a better check to see if the node has been removed.
+ if (node.parentNode == null) return;
+
+ _registerLifecycleRemove(element);
+ element.inserted();
+ });
+}
+
+void _registerLifecycleRemove(CustomElement element) {
+ // TODO(jmesserly): need fallback or polyfill for MutationObserver.
+ if (!MutationObserver.supported) return;
+
+ new MutationObserver((records, observer) {
+ var node = element.host;
+ for (var record in records) {
+ for (var removed in record.removedNodes) {
+ if (identical(node, removed)) {
+ observer.disconnect();
+ element.removed();
+ return;
+ }
+ }
+ }
+ }).observe(element.parentNode, childList: true);
+}
diff --git a/pkg/custom_element/lib/src/custom_tag_name.dart b/pkg/custom_element/lib/src/custom_tag_name.dart
new file mode 100644
index 0000000..72d9150
--- /dev/null
+++ b/pkg/custom_element/lib/src/custom_tag_name.dart
@@ -0,0 +1,27 @@
+// Copyright (c) 2013, 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 custom_element.src.custom_tag_name;
+
+/**
+ * Returns true if this is a valid custom element name. See:
+ * <https://dvcs.w3.org/hg/webcomponents/raw-file/tip/spec/custom/index.html#dfn-custom-element-name>
+ */
+bool isCustomTag(String name) {
+ if (!name.contains('-')) return false;
+
+ // These names have meaning in SVG or MathML, so they aren't allowed as custom
+ // tags.
+ var invalidNames = const {
+ 'annotation-xml': '',
+ 'color-profile': '',
+ 'font-face': '',
+ 'font-face-src': '',
+ 'font-face-uri': '',
+ 'font-face-format': '',
+ 'font-face-name': '',
+ 'missing-glyph': '',
+ };
+ return !invalidNames.containsKey(name);
+}
diff --git a/pkg/custom_element/pubspec.yaml b/pkg/custom_element/pubspec.yaml
new file mode 100644
index 0000000..e52b080
--- /dev/null
+++ b/pkg/custom_element/pubspec.yaml
@@ -0,0 +1,14 @@
+name: custom_element
+author: "Web UI Team <web-ui-dev@dartlang.org>"
+homepage: http://www.dartlang.org/
+description: >
+ Custom Elements let authors define their own elements. Authors associate code
+ with custom tag names, and then use those custom tag names as they would any
+ standard tag.
+dependencies:
+ meta: any
+ mutation_observer: any
+ # TODO(jmesserly): fix this, we should not depend on MDV.
+ mdv: any
+dev_dependencies:
+ unittest: any
diff --git a/pkg/custom_element/test/analyzer_test.dart b/pkg/custom_element/test/analyzer_test.dart
new file mode 100644
index 0000000..1ac251b
--- /dev/null
+++ b/pkg/custom_element/test/analyzer_test.dart
@@ -0,0 +1,13 @@
+// Copyright (c) 2013, 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 custom_element.test.analyzer_test;
+
+import 'package:custom_element/custom_element.dart';
+
+// @static-clean
+
+// This test ensures CustomElement compiles without errors.
+void main() {
+}
diff --git a/pkg/custom_element/test/custom_element_test.dart b/pkg/custom_element/test/custom_element_test.dart
new file mode 100644
index 0000000..e2f920a
--- /dev/null
+++ b/pkg/custom_element/test/custom_element_test.dart
@@ -0,0 +1,93 @@
+// Copyright (c) 2013, 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 custom_element.test.custom_element_test;
+
+import 'dart:async';
+import 'dart:html';
+import 'package:custom_element/custom_element.dart';
+import 'package:unittest/html_config.dart';
+import 'package:unittest/unittest.dart';
+
+main() {
+ useHtmlConfiguration();
+
+ // Load the MutationObserver polyfill.
+ HttpRequest.getString('/root_dart/pkg/mutation_observer/lib/'
+ 'mutation_observer.js').then((code) {
+ document.head.children.add(new ScriptElement()..text = code);
+
+ customElementTests();
+ });
+}
+
+customElementTests() {
+ test('register creates the element and calls lifecycle methods', () {
+ // Add element to the page.
+ var element = new Element.html('<fancy-button>foo bar</fancy-button>');
+ document.body.nodes.add(element);
+
+ var xtag = null;
+ registerCustomElement('fancy-button', () => xtag = new FancyButton());
+ expect(xtag, isNotNull, reason: 'FancyButton was created');
+ expect(element.xtag, xtag, reason: 'xtag pointer should be set');
+ expect(xtag.host, element, reason: 'host pointer should be set');
+ expect(xtag.lifecycle, ['created']);
+ return new Future(() {
+ expect(xtag.lifecycle, ['created', 'inserted']);
+ element.remove();
+ // TODO(jmesserly): the extra future here is to give IE9 time to deliver
+ // its event. This seems wrong. We'll probably need some cooperation
+ // between Dart and the polyfill to coordinate the microtask event loop.
+ return new Future(() => new Future(() {
+ expect(xtag.lifecycle, ['created', 'inserted', 'removed']);
+ }));
+ });
+ });
+
+ test('create a component in code', () {
+ var element = createElement('super-button');
+ expect(element.xtag, element, reason: 'element not registered');
+
+ var xtag = null;
+ registerCustomElement('super-button', () => xtag = new FancyButton());
+
+ element = createElement('super-button');
+ expect(xtag, isNotNull, reason: 'FancyButton was created');
+ expect(element.xtag, xtag, reason: 'xtag pointer should be set');
+ expect(xtag.host, element, reason: 'host pointer should be set');
+ expect(xtag.lifecycle, ['created']);
+ return new Future(() {
+ expect(xtag.lifecycle, ['created'], reason: 'not inserted into document');
+
+ document.body.nodes.add(element);
+ return new Future(() {
+ expect(xtag.lifecycle, ['created'],
+ reason: 'mutation observer not implemented yet');
+
+ element.remove();
+ return new Future(() {
+ expect(xtag.lifecycle, ['created'],
+ reason: 'mutation observer not implemented yet');
+ });
+ });
+ });
+ });
+}
+
+class FancyButton extends CustomElement {
+ final lifecycle = [];
+ created() {
+ super.created();
+ lifecycle.add('created');
+ }
+ inserted() {
+ super.inserted();
+ lifecycle.add('inserted');
+ }
+ removed() {
+ super.removed();
+ lifecycle.add('removed');
+ }
+}
diff --git a/pkg/docgen/bin/docgen.dart b/pkg/docgen/bin/docgen.dart
index d10c325..48b9071 100644
--- a/pkg/docgen/bin/docgen.dart
+++ b/pkg/docgen/bin/docgen.dart
@@ -22,7 +22,8 @@
outputToYaml: !results['json'],
includePrivate: results['include-private'],
includeSdk: results['parse-sdk'] || results['include-sdk'],
- parseSdk: results['parse-sdk']);
+ parseSdk: results['parse-sdk'],
+ append: results['append'] && new Directory('docs').existsSync());
}
/**
@@ -57,6 +58,9 @@
defaultsTo: false, negatable: false);
parser.addOption('package-root',
help: "Sets the package root of the library being analyzed.");
+ parser.addFlag('append',
+ help: 'Append to the docs folder, library_list.txt and index.txt',
+ defaultsTo: false, negatable: false);
return parser;
}
diff --git a/pkg/docgen/lib/docgen.dart b/pkg/docgen/lib/docgen.dart
index 6ad2609..2844d28 100644
--- a/pkg/docgen/lib/docgen.dart
+++ b/pkg/docgen/lib/docgen.dart
@@ -67,15 +67,19 @@
*/
Future<bool> docgen(List<String> files, {String packageRoot,
bool outputToYaml: true, bool includePrivate: false, bool includeSdk: false,
- bool parseSdk: false}) {
+ bool parseSdk: false, bool append: false}) {
+ if (!append) {
+ var dir = new Directory('docs');
+ if (dir.existsSync()) dir.deleteSync(recursive: true);
+ }
+
if (packageRoot == null && !parseSdk) {
- // TODO(janicejl): At the moment, if a single file is passed it, it is
- // assumed that it does not have a package root unless it is passed in by
- // the user. In future, find a better way to find the packageRoot and also
- // fully test finding the packageRoot.
- if (FileSystemEntity.typeSync(files.first)
- == FileSystemEntityType.DIRECTORY) {
+ var type = FileSystemEntity.typeSync(files.first);
+ if (type == FileSystemEntityType.DIRECTORY) {
packageRoot = _findPackageRoot(files.first);
+ } else if (type == FileSystemEntityType.FILE) {
+ logger.warning('WARNING: No package root defined. If Docgen fails, try '
+ 'again by setting the --package-root option.');
}
}
logger.info('Package Root: ${packageRoot}');
@@ -90,16 +94,13 @@
}
_documentLibraries(mirrorSystem.libraries.values,
includeSdk: includeSdk, includePrivate: includePrivate,
- outputToYaml: outputToYaml);
+ outputToYaml: outputToYaml, append: append);
return true;
});
}
List<String> _listLibraries(List<String> args) {
- // TODO(janicejl): At the moment, only have support to have either one file,
- // or one directory. This is because there can only be one package directory
- // since only one docgen is created per run.
if (args.length != 1) throw new UnsupportedError(USAGE);
var libraries = new List<String>();
var type = FileSystemEntity.typeSync(args[0]);
@@ -151,7 +152,7 @@
* documentation of the libraries.
*/
Future<MirrorSystem> getMirrorSystem(List<String> args, {String packageRoot,
- bool parseSdk:false}) {
+ bool parseSdk: false}) {
var libraries = !parseSdk ? _listLibraries(args) : _listSdk();
if (libraries.isEmpty) throw new StateError('No Libraries.');
// Finds the root of SDK library based off the location of docgen.
@@ -196,8 +197,8 @@
* Creates documentation for filtered libraries.
*/
void _documentLibraries(List<LibraryMirror> libraries,
- {bool includeSdk:false, bool includePrivate:false, bool
- outputToYaml:true}) {
+ {bool includeSdk: false, bool includePrivate: false,
+ bool outputToYaml: true, bool append: false}) {
libraries.forEach((lib) {
// Files belonging to the SDK have a uri that begins with 'dart:'.
if (includeSdk || !lib.uri.toString().startsWith('dart:')) {
@@ -209,14 +210,14 @@
// the libraries. This will help the viewer know what files are available
// to read in.
_writeToFile(listDir('docs').join('\n').replaceAll('docs/', ''),
- 'library_list.txt');
+ 'library_list.txt', append: append);
// Outputs all the qualified names documented. This will help generate search
// results.
- _writeToFile(qualifiedNameIndex.join('\n'), 'index.txt');
+ _writeToFile(qualifiedNameIndex.join('\n'), 'index.txt', append: append);
}
Library generateLibrary(dart2js.Dart2JsLibraryMirror library,
- {bool includePrivate:false}) {
+ {bool includePrivate: false}) {
_currentLibrary = library;
var result = new Library(library.qualifiedName, _getComment(library),
_getVariables(library.variables, includePrivate),
@@ -443,7 +444,7 @@
/**
* Writes text to a file in the 'docs' directory.
*/
-void _writeToFile(String text, String filename) {
+void _writeToFile(String text, String filename, {bool append: false}) {
Directory dir = new Directory('docs');
if (!dir.existsSync()) {
dir.createSync();
@@ -452,8 +453,7 @@
if (!file.existsSync()) {
file.createSync();
}
- file.openSync();
- file.writeAsString(text);
+ file.writeAsString(text, mode: append ? FileMode.APPEND : FileMode.WRITE);
}
/**
diff --git a/pkg/fixnum/lib/src/int32.dart b/pkg/fixnum/lib/src/int32.dart
index 84d9bfc..fb78a48 100644
--- a/pkg/fixnum/lib/src/int32.dart
+++ b/pkg/fixnum/lib/src/int32.dart
@@ -8,34 +8,34 @@
* An immutable 32-bit signed integer, in the range [-2^31, 2^31 - 1].
* Arithmetic operations may overflow in order to maintain this range.
*/
-class int32 implements intx {
+class Int32 implements IntX {
/**
- * The maximum positive value attainable by an [int32], namely
+ * The maximum positive value attainable by an [Int32], namely
* 2147483647.
*/
- static const int32 MAX_VALUE = const int32._internal(0x7FFFFFFF);
+ static const Int32 MAX_VALUE = const Int32._internal(0x7FFFFFFF);
/**
- * The minimum positive value attainable by an [int32], namely
+ * The minimum positive value attainable by an [Int32], namely
* -2147483648.
*/
- static int32 MIN_VALUE = const int32._internal(-0x80000000);
+ static const Int32 MIN_VALUE = const Int32._internal(-0x80000000);
/**
- * An [int32] constant equal to 0.
+ * An [Int32] constant equal to 0.
*/
- static int32 ZERO = const int32._internal(0);
+ static const Int32 ZERO = const Int32._internal(0);
/**
- * An [int32] constant equal to 1.
+ * An [Int32] constant equal to 1.
*/
- static int32 ONE = const int32._internal(1);
+ static const Int32 ONE = const Int32._internal(1);
/**
- * An [int32] constant equal to 2.
+ * An [Int32] constant equal to 2.
*/
- static int32 TWO = const int32._internal(2);
+ static const Int32 TWO = const Int32._internal(2);
// Hex digit char codes
static const int _CC_0 = 48; // '0'.codeUnitAt(0)
@@ -59,14 +59,14 @@
/**
* Parses a [String] in a given [radix] between 2 and 16 and returns an
- * [int32].
+ * [Int32].
*/
// TODO(rice) - Make this faster by converting several digits at once.
- static int32 parseRadix(String s, int radix) {
+ static Int32 parseRadix(String s, int radix) {
if ((radix <= 1) || (radix > 16)) {
- throw "Bad radix: $radix";
+ throw new ArgumentError("Bad radix: $radix");
}
- int32 x = ZERO;
+ Int32 x = ZERO;
for (int i = 0; i < s.length; i++) {
int c = s.codeUnitAt(i);
int digit = _decodeHex(c);
@@ -79,14 +79,14 @@
}
/**
- * Parses a decimal [String] and returns an [int32].
+ * Parses a decimal [String] and returns an [Int32].
*/
- static int32 parseInt(String s) => new int32.fromInt(int.parse(s));
+ static Int32 parseInt(String s) => new Int32.fromInt(int.parse(s));
/**
- * Parses a hexadecimal [String] and returns an [int32].
+ * Parses a hexadecimal [String] and returns an [Int32].
*/
- static int32 parseHex(String s) => parseRadix(s, 16);
+ static Int32 parseHex(String s) => parseRadix(s, 16);
// Assumes i is <= 32-bit.
static int _bitCount(int i) {
@@ -130,18 +130,18 @@
// The internal value, kept in the range [MIN_VALUE, MAX_VALUE].
final int _i;
- const int32._internal(int i) : _i = i;
+ const Int32._internal(int i) : _i = i;
/**
- * Constructs an [int32] from an [int]. Only the low 32 bits of the input
+ * Constructs an [Int32] from an [int]. Only the low 32 bits of the input
* are used.
*/
- int32.fromInt(int i) : _i = (i & 0x7fffffff) - (i & 0x80000000);
+ Int32.fromInt(int i) : _i = (i & 0x7fffffff) - (i & 0x80000000);
// Returns the [int] representation of the specified value. Throws
// [ArgumentError] for non-integer arguments.
int _toInt(val) {
- if (val is int32) {
+ if (val is Int32) {
return val._i;
} else if (val is int) {
return val;
@@ -151,99 +151,99 @@
// The +, -, * , &, |, and ^ operaters deal with types as follows:
//
- // int32 + int => int32
- // int32 + int32 => int32
- // int32 + int64 => int64
+ // Int32 + int => Int32
+ // Int32 + Int32 => Int32
+ // Int32 + Int64 => Int64
//
- // The %, ~/ and remainder operators return an int32 even with an int64
+ // The %, ~/ and remainder operators return an Int32 even with an Int64
// argument, since the result cannot be greater than the value on the
// left-hand side:
//
- // int32 % int => int32
- // int32 % int32 => int32
- // int32 % int64 => int32
+ // Int32 % int => Int32
+ // Int32 % Int32 => Int32
+ // Int32 % Int64 => Int32
- intx operator +(other) {
- if (other is int64) {
+ IntX operator +(other) {
+ if (other is Int64) {
return this.toInt64() + other;
}
- return new int32.fromInt(_i + _toInt(other));
+ return new Int32.fromInt(_i + _toInt(other));
}
- intx operator -(other) {
- if (other is int64) {
+ IntX operator -(other) {
+ if (other is Int64) {
return this.toInt64() - other;
}
- return new int32.fromInt(_i - _toInt(other));
+ return new Int32.fromInt(_i - _toInt(other));
}
- int32 operator -() => new int32.fromInt(-_i);
+ Int32 operator -() => new Int32.fromInt(-_i);
- intx operator *(other) {
- if (other is int64) {
+ IntX operator *(other) {
+ if (other is Int64) {
return this.toInt64() * other;
}
// TODO(rice) - optimize
return (this.toInt64() * other).toInt32();
}
- int32 operator %(other) {
- if (other is int64) {
- // Result will be int32
+ Int32 operator %(other) {
+ if (other is Int64) {
+ // Result will be Int32
return (this.toInt64() % other).toInt32();
}
- return new int32.fromInt(_i % _toInt(other));
+ return new Int32.fromInt(_i % _toInt(other));
}
- int32 operator ~/(other) {
- if (other is int64) {
+ Int32 operator ~/(other) {
+ if (other is Int64) {
return (this.toInt64() ~/ other).toInt32();
}
- return new int32.fromInt(_i ~/ _toInt(other));
+ return new Int32.fromInt(_i ~/ _toInt(other));
}
- int32 remainder(other) {
- if (other is int64) {
- int64 t = this.toInt64();
+ Int32 remainder(other) {
+ if (other is Int64) {
+ Int64 t = this.toInt64();
return (t - (t ~/ other) * other).toInt32();
}
return this - (this ~/ other) * other;
}
- int32 operator &(other) {
- if (other is int64) {
+ Int32 operator &(other) {
+ if (other is Int64) {
return (this.toInt64() & other).toInt32();
}
- return new int32.fromInt(_i & _toInt(other));
+ return new Int32.fromInt(_i & _toInt(other));
}
- int32 operator |(other) {
- if (other is int64) {
+ Int32 operator |(other) {
+ if (other is Int64) {
return (this.toInt64() | other).toInt32();
}
- return new int32.fromInt(_i | _toInt(other));
+ return new Int32.fromInt(_i | _toInt(other));
}
- int32 operator ^(other) {
- if (other is int64) {
+ Int32 operator ^(other) {
+ if (other is Int64) {
return (this.toInt64() ^ other).toInt32();
}
- return new int32.fromInt(_i ^ _toInt(other));
+ return new Int32.fromInt(_i ^ _toInt(other));
}
- int32 operator ~() => new int32.fromInt(~_i);
+ Int32 operator ~() => new Int32.fromInt(~_i);
- int32 operator <<(int n) {
+ Int32 operator <<(int n) {
if (n < 0) {
- throw new ArgumentError("$n");
+ throw new ArgumentError(n);
}
n &= 31;
- return new int32.fromInt(_i << n);
+ return new Int32.fromInt(_i << n);
}
- int32 operator >>(int n) {
+ Int32 operator >>(int n) {
if (n < 0) {
- throw new ArgumentError("$n");
+ throw new ArgumentError(n);
}
n &= 31;
int value;
@@ -252,12 +252,12 @@
} else {
value = (_i >> n) | (0xffffffff << (32 - n));
}
- return new int32.fromInt(value);
+ return new Int32.fromInt(value);
}
- int32 shiftRightUnsigned(int n) {
+ Int32 shiftRightUnsigned(int n) {
if (n < 0) {
- throw new ArgumentError("$n");
+ throw new ArgumentError(n);
}
n &= 31;
int value;
@@ -266,17 +266,17 @@
} else {
value = (_i >> n) & ((1 << (32 - n)) - 1);
}
- return new int32.fromInt(value);
+ return new Int32.fromInt(value);
}
/**
- * Returns [true] if this [int32] has the same numeric value as the
- * given object. The argument may be an [int] or an [intx].
+ * Returns [true] if this [Int32] has the same numeric value as the
+ * given object. The argument may be an [int] or an [IntX].
*/
bool operator ==(other) {
- if (other is int32) {
+ if (other is Int32) {
return _i == other._i;
- } else if (other is int64) {
+ } else if (other is Int64) {
return this.toInt64() == other;
} else if (other is int) {
return _i == other;
@@ -285,35 +285,35 @@
}
int compareTo(Comparable other) {
- if (other is int64) {
+ if (other is Int64) {
return this.toInt64().compareTo(other);
}
return _i.compareTo(_toInt(other));
}
bool operator <(other) {
- if (other is int64) {
+ if (other is Int64) {
return this.toInt64() < other;
}
return _i < _toInt(other);
}
bool operator <=(other) {
- if (other is int64) {
+ if (other is Int64) {
return this.toInt64() <= other;
}
return _i <= _toInt(other);
}
bool operator >(other) {
- if (other is int64) {
+ if (other is Int64) {
return this.toInt64() > other;
}
return _i > _toInt(other);
}
bool operator >=(other) {
- if (other is int64) {
+ if (other is Int64) {
return this.toInt64() >= other;
}
return _i >= _toInt(other);
@@ -328,7 +328,7 @@
int get hashCode => _i;
- int32 abs() => _i < 0 ? new int32.fromInt(-_i) : this;
+ Int32 abs() => _i < 0 ? new Int32.fromInt(-_i) : this;
int numberOfLeadingZeros() => _numberOfLeadingZeros(_i);
int numberOfTrailingZeros() => _numberOfTrailingZeros(_i);
@@ -343,8 +343,8 @@
}
int toInt() => _i;
- int32 toInt32() => this;
- int64 toInt64() => new int64.fromInt(_i);
+ Int32 toInt32() => this;
+ Int64 toInt64() => new Int64.fromInt(_i);
String toString() => _i.toString();
String toHexString() => _i.toRadixString(16);
diff --git a/pkg/fixnum/lib/src/int64.dart b/pkg/fixnum/lib/src/int64.dart
index a179105..1a9d73a 100644
--- a/pkg/fixnum/lib/src/int64.dart
+++ b/pkg/fixnum/lib/src/int64.dart
@@ -8,7 +8,7 @@
* An immutable 64-bit signed integer, in the range [-2^63, 2^63 - 1].
* Arithmetic operations may overflow in order to maintain this range.
*/
-class int64 implements intx {
+class Int64 implements IntX {
// A 64-bit integer is represented internally as three non-negative
// integers, storing the 22 low, 22 middle, and 20 high bits of the
@@ -16,7 +16,7 @@
// [0, 2^22 - 1] and _h (high) is in the range [0, 2^20 - 1].
int _l, _m, _h;
- // Note: instances of int64 are immutable outside of this library,
+ // Note: instances of [Int64] are immutable outside of this library,
// therefore we may return a reference to an existing instance.
// We take care to perform mutation only on internally-generated
// instances before they are exposed to external code.
@@ -31,11 +31,11 @@
static const int _SIGN_BIT_VALUE = 524288; // 1 << _SIGN_BIT
// Cached constants
- static int64 _MAX_VALUE;
- static int64 _MIN_VALUE;
- static int64 _ZERO;
- static int64 _ONE;
- static int64 _TWO;
+ static Int64 _MAX_VALUE;
+ static Int64 _MIN_VALUE;
+ static Int64 _ZERO;
+ static Int64 _ONE;
+ static Int64 _TWO;
// Precompute the radix strings for MIN_VALUE to avoid the problem
// of overflow of -MIN_VALUE.
@@ -59,70 +59,70 @@
];
// The remainder of the last divide operation.
- static int64 _remainder;
+ static Int64 _remainder;
/**
- * The maximum positive value attainable by an [int64], namely
+ * The maximum positive value attainable by an [Int64], namely
* 9,223,372,036,854,775,807.
*/
- static int64 get MAX_VALUE {
+ static Int64 get MAX_VALUE {
if (_MAX_VALUE == null) {
- _MAX_VALUE = new int64._bits(_MASK, _MASK, _MASK_2 >> 1);
+ _MAX_VALUE = new Int64._bits(_MASK, _MASK, _MASK_2 >> 1);
}
return _MAX_VALUE;
}
/**
- * The minimum positive value attainable by an [int64], namely
+ * The minimum positive value attainable by an [Int64], namely
* -9,223,372,036,854,775,808.
*/
- static int64 get MIN_VALUE {
+ static Int64 get MIN_VALUE {
if (_MIN_VALUE == null) {
- _MIN_VALUE = new int64._bits(0, 0, _SIGN_BIT_VALUE);
+ _MIN_VALUE = new Int64._bits(0, 0, _SIGN_BIT_VALUE);
}
return _MIN_VALUE;
}
/**
- * An [int64] constant equal to 0.
+ * An [Int64] constant equal to 0.
*/
- static int64 get ZERO {
+ static Int64 get ZERO {
if (_ZERO == null) {
- _ZERO = new int64();
+ _ZERO = new Int64();
}
return _ZERO;
}
/**
- * An [int64] constant equal to 1.
+ * An [Int64] constant equal to 1.
*/
- static int64 get ONE {
+ static Int64 get ONE {
if (_ONE == null) {
- _ONE = new int64._bits(1, 0, 0);
+ _ONE = new Int64._bits(1, 0, 0);
}
return _ONE;
}
/**
- * An [int64] constant equal to 2.
+ * An [Int64] constant equal to 2.
*/
- static int64 get TWO {
+ static Int64 get TWO {
if (_TWO == null) {
- _TWO = new int64._bits(2, 0, 0);
+ _TWO = new Int64._bits(2, 0, 0);
}
return _TWO;
}
/**
* Parses a [String] in a given [radix] between 2 and 16 and returns an
- * [int64].
+ * [Int64].
*/
// TODO(rice) - make this faster by converting several digits at once.
- static int64 parseRadix(String s, int radix) {
+ static Int64 parseRadix(String s, int radix) {
if ((radix <= 1) || (radix > 16)) {
- throw "Bad radix: $radix";
+ throw new ArgumentError("Bad radix: $radix");
}
- int64 x = ZERO;
+ Int64 x = ZERO;
int i = 0;
bool negative = false;
if (s[0] == '-') {
@@ -131,7 +131,7 @@
}
for (; i < s.length; i++) {
int c = s.codeUnitAt(i);
- int digit = int32._decodeHex(c);
+ int digit = Int32._decodeHex(c);
if (digit < 0 || digit >= radix) {
throw new Exception("Non-radix char code: $c");
}
@@ -141,28 +141,28 @@
}
/**
- * Parses a decimal [String] and returns an [int64].
+ * Parses a decimal [String] and returns an [Int64].
*/
- static int64 parseInt(String s) => parseRadix(s, 10);
+ static Int64 parseInt(String s) => parseRadix(s, 10);
/**
- * Parses a hexadecimal [String] and returns an [int64].
+ * Parses a hexadecimal [String] and returns an [Int64].
*/
- static int64 parseHex(String s) => parseRadix(s, 16);
+ static Int64 parseHex(String s) => parseRadix(s, 16);
//
// Public constructors
//
/**
- * Constructs an [int64] equal to 0.
+ * Constructs an [Int64] equal to 0.
*/
- int64() : _l = 0, _m = 0, _h = 0;
+ Int64() : _l = 0, _m = 0, _h = 0;
/**
- * Constructs an [int64] with a given [int] value.
+ * Constructs an [Int64] with a given [int] value.
*/
- int64.fromInt(int value) {
+ Int64.fromInt(int value) {
bool negative = false;
if (value < 0) {
negative = true;
@@ -188,7 +188,7 @@
}
}
- factory int64.fromBytes(List<int> bytes) {
+ factory Int64.fromBytes(List<int> bytes) {
int top = bytes[7] & 0xff;
top <<= 8;
top |= bytes[6] & 0xff;
@@ -205,10 +205,10 @@
bottom <<= 8;
bottom |= bytes[0] & 0xff;
- return new int64.fromInts(top, bottom);
+ return new Int64.fromInts(top, bottom);
}
- factory int64.fromBytesBigEndian(List<int> bytes) {
+ factory Int64.fromBytesBigEndian(List<int> bytes) {
int top = bytes[0] & 0xff;
top <<= 8;
top |= bytes[1] & 0xff;
@@ -225,14 +225,14 @@
bottom <<= 8;
bottom |= bytes[7] & 0xff;
- return new int64.fromInts(top, bottom);
+ return new Int64.fromInts(top, bottom);
}
/**
- * Constructs an [int64] from a pair of 32-bit integers having the value
+ * Constructs an [Int64] from a pair of 32-bit integers having the value
* [:((top & 0xffffffff) << 32) | (bottom & 0xffffffff):].
*/
- int64.fromInts(int top, int bottom) {
+ Int64.fromInts(int top, int bottom) {
top &= 0xffffffff;
bottom &= 0xffffffff;
_l = bottom & _MASK;
@@ -240,50 +240,50 @@
_h = (top >> 12) & _MASK_2;
}
- // Returns the [int64] representation of the specified value. Throws
+ // Returns the [Int64] representation of the specified value. Throws
// [ArgumentError] for non-integer arguments.
- int64 _promote(val) {
- if (val is int64) {
+ Int64 _promote(val) {
+ if (val is Int64) {
return val;
} else if (val is int) {
- return new int64.fromInt(val);
- } else if (val is int32) {
+ return new Int64.fromInt(val);
+ } else if (val is Int32) {
return val.toInt64();
}
throw new ArgumentError(val);
}
- int64 operator +(other) {
- int64 o = _promote(other);
+ Int64 operator +(other) {
+ Int64 o = _promote(other);
int sum0 = _l + o._l;
int sum1 = _m + o._m + _shiftRight(sum0, _BITS);
int sum2 = _h + o._h + _shiftRight(sum1, _BITS);
- int64 result = new int64._bits(sum0 & _MASK, sum1 & _MASK, sum2 & _MASK_2);
+ Int64 result = new Int64._bits(sum0 & _MASK, sum1 & _MASK, sum2 & _MASK_2);
return result;
}
- int64 operator -(other) {
- int64 o = _promote(other);
+ Int64 operator -(other) {
+ Int64 o = _promote(other);
int sum0 = _l - o._l;
int sum1 = _m - o._m + _shiftRight(sum0, _BITS);
int sum2 = _h - o._h + _shiftRight(sum1, _BITS);
- int64 result = new int64._bits(sum0 & _MASK, sum1 & _MASK, sum2 & _MASK_2);
+ Int64 result = new Int64._bits(sum0 & _MASK, sum1 & _MASK, sum2 & _MASK_2);
return result;
}
- int64 operator -() {
+ Int64 operator -() {
// Like 0 - this.
int sum0 = -_l;
int sum1 = -_m + _shiftRight(sum0, _BITS);
int sum2 = -_h + _shiftRight(sum1, _BITS);
- return new int64._bits(sum0 & _MASK, sum1 & _MASK, sum2 & _MASK_2);
+ return new Int64._bits(sum0 & _MASK, sum1 & _MASK, sum2 & _MASK_2);
}
- int64 operator *(other) {
- int64 o = _promote(other);
+ Int64 operator *(other) {
+ Int64 o = _promote(other);
// Grab 13-bit chunks.
int a0 = _l & 0x1fff;
@@ -363,65 +363,65 @@
c1 &= _MASK;
c2 &= _MASK_2;
- return new int64._bits(c0, c1, c2);
+ return new Int64._bits(c0, c1, c2);
}
- int64 operator %(other) {
+ Int64 operator %(other) {
if (other.isZero) {
throw new IntegerDivisionByZeroException();
}
if (this.isZero) {
return ZERO;
}
- int64 o = _promote(other).abs();
+ Int64 o = _promote(other).abs();
_divMod(this, o, true);
return _remainder < 0 ? (_remainder + o) : _remainder;
}
- int64 operator ~/(other) => _divMod(this, _promote(other), false);
+ Int64 operator ~/(other) => _divMod(this, _promote(other), false);
- // int64 remainder(other) => this - (this ~/ other) * other;
- int64 remainder(other) {
+ // Int64 remainder(other) => this - (this ~/ other) * other;
+ Int64 remainder(other) {
if (other.isZero) {
throw new IntegerDivisionByZeroException();
}
- int64 o = _promote(other).abs();
+ Int64 o = _promote(other).abs();
_divMod(this, o, true);
return _remainder;
}
- int64 operator &(other) {
- int64 o = _promote(other);
+ Int64 operator &(other) {
+ Int64 o = _promote(other);
int a0 = _l & o._l;
int a1 = _m & o._m;
int a2 = _h & o._h;
- return new int64._bits(a0, a1, a2);
+ return new Int64._bits(a0, a1, a2);
}
- int64 operator |(other) {
- int64 o = _promote(other);
+ Int64 operator |(other) {
+ Int64 o = _promote(other);
int a0 = _l | o._l;
int a1 = _m | o._m;
int a2 = _h | o._h;
- return new int64._bits(a0, a1, a2);
+ return new Int64._bits(a0, a1, a2);
}
- int64 operator ^(other) {
- int64 o = _promote(other);
+ Int64 operator ^(other) {
+ Int64 o = _promote(other);
int a0 = _l ^ o._l;
int a1 = _m ^ o._m;
int a2 = _h ^ o._h;
- return new int64._bits(a0, a1, a2);
+ return new Int64._bits(a0, a1, a2);
}
- int64 operator ~() {
- var result = new int64._bits((~_l) & _MASK, (~_m) & _MASK, (~_h) & _MASK_2);
+ Int64 operator ~() {
+ var result = new Int64._bits((~_l) & _MASK, (~_m) & _MASK, (~_h) & _MASK_2);
return result;
}
- int64 operator <<(int n) {
+ Int64 operator <<(int n) {
if (n < 0) {
- throw new ArgumentError("$n");
+ throw new ArgumentError(n);
}
n &= 63;
@@ -440,12 +440,12 @@
res2 = _l << (n - _BITS01);
}
- return new int64._bits(res0 & _MASK, res1 & _MASK, res2 & _MASK_2);
+ return new Int64._bits(res0 & _MASK, res1 & _MASK, res2 & _MASK_2);
}
- int64 operator >>(int n) {
+ Int64 operator >>(int n) {
if (n < 0) {
- throw new ArgumentError("$n");
+ throw new ArgumentError(n);
}
n &= 63;
@@ -481,12 +481,12 @@
}
}
- return new int64._bits(res0 & _MASK, res1 & _MASK, res2 & _MASK_2);
+ return new Int64._bits(res0 & _MASK, res1 & _MASK, res2 & _MASK_2);
}
- int64 shiftRightUnsigned(int n) {
+ Int64 shiftRightUnsigned(int n) {
if (n < 0) {
- throw new ArgumentError("$n");
+ throw new ArgumentError(n);
}
n &= 63;
@@ -506,20 +506,20 @@
res0 = a2 >> (n - _BITS01);
}
- return new int64._bits(res0 & _MASK, res1 & _MASK, res2 & _MASK_2);
+ return new Int64._bits(res0 & _MASK, res1 & _MASK, res2 & _MASK_2);
}
/**
- * Returns [true] if this [int64] has the same numeric value as the
- * given object. The argument may be an [int] or an [intx].
+ * Returns [true] if this [Int64] has the same numeric value as the
+ * given object. The argument may be an [int] or an [IntX].
*/
bool operator ==(other) {
- int64 o;
- if (other is int64) {
+ Int64 o;
+ if (other is Int64) {
o = other;
} else if (other is int) {
- o = new int64.fromInt(other);
- } else if (other is int32) {
+ o = new Int64.fromInt(other);
+ } else if (other is Int32) {
o = other.toInt64();
}
if (o != null) {
@@ -529,7 +529,7 @@
}
int compareTo(Comparable other) {
- int64 o = _promote(other);
+ Int64 o = _promote(other);
int signa = _h >> (_BITS2 - 1);
int signb = o._h >> (_BITS2 - 1);
if (signa != signb) {
@@ -577,7 +577,7 @@
bool get isZero => _h == 0 && _m == 0 && _l == 0;
/**
- * Returns a hash code based on all the bits of this [int64].
+ * Returns a hash code based on all the bits of this [Int64].
*/
int get hashCode {
int bottom = ((_m & 0x3ff) << _BITS) | _l;
@@ -585,20 +585,20 @@
return bottom ^ top;
}
- int64 abs() {
+ Int64 abs() {
return this < 0 ? -this : this;
}
/**
- * Returns the number of leading zeros in this [int64] as an [int]
+ * Returns the number of leading zeros in this [Int64] as an [int]
* between 0 and 64.
*/
int numberOfLeadingZeros() {
- int b2 = int32._numberOfLeadingZeros(_h);
+ int b2 = Int32._numberOfLeadingZeros(_h);
if (b2 == 32) {
- int b1 = int32._numberOfLeadingZeros(_m);
+ int b1 = Int32._numberOfLeadingZeros(_m);
if (b1 == 32) {
- return int32._numberOfLeadingZeros(_l) + 32;
+ return Int32._numberOfLeadingZeros(_l) + 32;
} else {
return b1 + _BITS2 - (32 - _BITS);
}
@@ -608,21 +608,21 @@
}
/**
- * Returns the number of trailing zeros in this [int64] as an [int]
+ * Returns the number of trailing zeros in this [Int64] as an [int]
* between 0 and 64.
*/
int numberOfTrailingZeros() {
- int zeros = int32._numberOfTrailingZeros(_l);
+ int zeros = Int32._numberOfTrailingZeros(_l);
if (zeros < 32) {
return zeros;
}
- zeros = int32._numberOfTrailingZeros(_m);
+ zeros = Int32._numberOfTrailingZeros(_m);
if (zeros < 32) {
return _BITS + zeros;
}
- zeros = int32._numberOfTrailingZeros(_h);
+ zeros = Int32._numberOfTrailingZeros(_h);
if (zeros < 32) {
return _BITS01 + zeros;
}
@@ -665,23 +665,23 @@
}
/**
- * Returns an [int32] containing the low 32 bits of this [int64].
+ * Returns an [Int32] containing the low 32 bits of this [Int64].
*/
- int32 toInt32() {
- return new int32.fromInt(((_m & 0x3ff) << _BITS) | _l);
+ Int32 toInt32() {
+ return new Int32.fromInt(((_m & 0x3ff) << _BITS) | _l);
}
/**
* Returns [this].
*/
- int64 toInt64() => this;
+ Int64 toInt64() => this;
/**
- * Returns the value of this [int64] as a decimal [String].
+ * Returns the value of this [Int64] as a decimal [String].
*/
// TODO(rice) - Make this faster by converting several digits at once.
String toString() {
- int64 a = this;
+ Int64 a = this;
if (a.isZero) {
return "0";
}
@@ -696,7 +696,7 @@
a = -a;
}
- int64 ten = new int64._bits(10, 0, 0);
+ Int64 ten = new Int64._bits(10, 0, 0);
while (!a.isZero) {
a = _divMod(a, ten, true);
result = "${_remainder._l}$result";
@@ -709,12 +709,12 @@
// TODO(rice) - Make this faster by avoiding arithmetic.
String toHexString() {
- int64 x = new int64._copy(this);
+ Int64 x = new Int64._copy(this);
if (isZero) {
return "0";
}
String hexStr = "";
- int64 digit_f = new int64.fromInt(0xf);
+ Int64 digit_f = new Int64.fromInt(0xf);
while (!x.isZero) {
int digit = x._l & 0xf;
hexStr = "${_hexDigit(digit)}$hexStr";
@@ -725,9 +725,9 @@
String toRadixString(int radix) {
if ((radix <= 1) || (radix > 16)) {
- throw "Bad radix: $radix";
+ throw new ArgumentError("Bad radix: $radix");
}
- int64 a = this;
+ Int64 a = this;
if (a.isZero) {
return "0";
}
@@ -742,7 +742,7 @@
a = -a;
}
- int64 r = new int64._bits(radix, 0, 0);
+ Int64 r = new Int64._bits(radix, 0, 0);
while (!a.isZero) {
a = _divMod(a, r, true);
result = "${_hexDigit(_remainder._l)}$result";
@@ -751,19 +751,19 @@
}
String toDebugString() {
- return "int64[_l=$_l, _m=$_m, _h=$_h]";
+ return "Int64[_l=$_l, _m=$_m, _h=$_h]";
}
/**
- * Constructs an [int64] with a given bitwise representation. No validation
+ * Constructs an [Int64] with a given bitwise representation. No validation
* is performed.
*/
- int64._bits(int this._l, int this._m, int this._h);
+ Int64._bits(int this._l, int this._m, int this._h);
/**
- * Constructs an [int64] with the same value as an existing [int64].
+ * Constructs an [Int64] with the same value as an existing [Int64].
*/
- int64._copy(int64 other) {
+ Int64._copy(Int64 other) {
_l = other._l;
_m = other._m;
_h = other._h;
@@ -848,7 +848,7 @@
* }
*/
// Note: mutates [a].
- static bool _trialSubtract(int64 a, int64 b) {
+ static bool _trialSubtract(Int64 a, Int64 b) {
// Early exit.
int sum2 = a._h - b._h;
if (sum2 < 0) {
@@ -871,15 +871,15 @@
}
// Note: mutates [a] via _trialSubtract.
- static int64 _divModHelper(int64 a, int64 b,
+ static Int64 _divModHelper(Int64 a, Int64 b,
bool negative, bool aIsNegative, bool aIsMinValue,
bool computeRemainder) {
// Align the leading one bits of a and b by shifting b left.
int shift = b.numberOfLeadingZeros() - a.numberOfLeadingZeros();
- int64 bshift = b << shift;
+ Int64 bshift = b << shift;
// Quotient must be a new instance since we mutate it.
- int64 quotient = new int64();
+ Int64 quotient = new Int64();
while (shift >= 0) {
bool gte = _trialSubtract(a, bshift);
if (gte) {
@@ -911,7 +911,7 @@
return quotient;
}
- int64 _divModByMinValue(bool computeRemainder) {
+ Int64 _divModByMinValue(bool computeRemainder) {
// MIN_VALUE / MIN_VALUE == 1, remainder = 0
// (x != MIN_VALUE) / MIN_VALUE == 0, remainder == x
if (isMinValue) {
@@ -930,7 +930,7 @@
* this &= ((1L << bits) - 1)
*/
// Note: mutates [this].
- int64 _maskRight(int bits) {
+ Int64 _maskRight(int bits) {
int b0, b1, b2;
if (bits <= _BITS) {
b0 = _l & ((1 << bits) - 1);
@@ -950,16 +950,16 @@
_h = b2;
}
- static int64 _divModByShift(int64 a, int bpower, bool negative, bool aIsCopy,
+ static Int64 _divModByShift(Int64 a, int bpower, bool negative, bool aIsCopy,
bool aIsNegative, bool computeRemainder) {
- int64 c = a >> bpower;
+ Int64 c = a >> bpower;
if (negative) {
c._negate();
}
if (computeRemainder) {
if (!aIsCopy) {
- a = new int64._copy(a);
+ a = new Int64._copy(a);
}
a._maskRight(bpower);
if (aIsNegative) {
@@ -991,19 +991,19 @@
return -1;
}
if (h == 0 && m == 0 && l != 0) {
- return int32._numberOfTrailingZeros(l);
+ return Int32._numberOfTrailingZeros(l);
}
if (h == 0 && m != 0 && l == 0) {
- return int32._numberOfTrailingZeros(m) + _BITS;
+ return Int32._numberOfTrailingZeros(m) + _BITS;
}
if (h != 0 && m == 0 && l == 0) {
- return int32._numberOfTrailingZeros(h) + _BITS01;
+ return Int32._numberOfTrailingZeros(h) + _BITS01;
}
return -1;
}
- static int64 _divMod(int64 a, int64 b, bool computeRemainder) {
+ static Int64 _divMod(Int64 a, Int64 b, bool computeRemainder) {
if (b.isZero) {
throw new IntegerDivisionByZeroException();
}
@@ -1029,7 +1029,7 @@
// True if the original value of a is negative.
bool aIsNegative = false;
- // True if the original value of a is int64.MIN_VALUE.
+ // True if the original value of a is Int64.MIN_VALUE.
bool aIsMinValue = false;
/*
@@ -1056,12 +1056,12 @@
// If b is not a power of two, treat -a as MAX_VALUE (instead of the
// actual value (MAX_VALUE + 1)).
if (bpower == -1) {
- a = new int64._copy(MAX_VALUE);
+ a = new Int64._copy(MAX_VALUE);
aIsCopy = true;
negative = !negative;
} else {
// Signed shift of MIN_VALUE produces the right answer.
- int64 c = a >> bpower;
+ Int64 c = a >> bpower;
if (negative) {
c._negate();
}
@@ -1090,14 +1090,14 @@
if (aIsNegative) {
_remainder = -a;
} else {
- _remainder = aIsCopy ? a : new int64._copy(a);
+ _remainder = aIsCopy ? a : new Int64._copy(a);
}
}
return ZERO;
}
// Generate the quotient using bit-at-a-time long division.
- return _divModHelper(aIsCopy ? a : new int64._copy(a), b, negative,
+ return _divModHelper(aIsCopy ? a : new Int64._copy(a), b, negative,
aIsNegative, aIsMinValue, computeRemainder);
}
}
diff --git a/pkg/fixnum/lib/src/intx.dart b/pkg/fixnum/lib/src/intx.dart
index 582fe72..a2bb0f0 100644
--- a/pkg/fixnum/lib/src/intx.dart
+++ b/pkg/fixnum/lib/src/intx.dart
@@ -7,32 +7,32 @@
/**
* A fixed-precision integer.
*/
-abstract class intx implements Comparable {
+abstract class IntX implements Comparable {
// Arithmetic operations.
- intx operator +(other);
- intx operator -(other);
+ IntX operator +(other);
+ IntX operator -(other);
// The unary '-' operator. Note that -MIN_VALUE will be equal
// to MIN_VALUE due to overflow.
- intx operator -();
- intx operator *(other);
- intx operator %(other);
+ IntX operator -();
+ IntX operator *(other);
+ IntX operator %(other);
// Truncating division.
- intx operator ~/(other);
- intx remainder(other);
+ IntX operator ~/(other);
+ IntX remainder(other);
// Note: no / operator
// Bit-operations.
- intx operator &(other);
- intx operator |(other);
- intx operator ^(other);
- intx operator ~();
- intx operator <<(int shiftAmount);
- intx operator >>(int shiftAmount);
- intx shiftRightUnsigned(int shiftAmount);
+ IntX operator &(other);
+ IntX operator |(other);
+ IntX operator ^(other);
+ IntX operator ~();
+ IntX operator <<(int shiftAmount);
+ IntX operator >>(int shiftAmount);
+ IntX shiftRightUnsigned(int shiftAmount);
- // Relational operations, may be applied to intx or int.
+ // Relational operations, may be applied to IntX or int.
int compareTo(Comparable other);
bool operator ==(other);
bool operator <(other);
@@ -50,55 +50,55 @@
int get hashCode;
- intx abs();
+ IntX abs();
/**
- * Returns the number of leading zeros in this [intx] as an [int]
+ * Returns the number of leading zeros in this [IntX] as an [int]
* between 0 and 64.
*/
int numberOfLeadingZeros();
/**
- * Returns the number of trailing zeros in this [intx] as an [int]
+ * Returns the number of trailing zeros in this [IntX] as an [int]
* between 0 and 64.
*/
int numberOfTrailingZeros();
/**
- * Converts this [intx] to a [List] of [int], starting with the least
+ * Converts this [IntX] to a [List] of [int], starting with the least
* significant byte.
*/
List<int> toBytes();
/**
- * Converts this [intx] to an [int]. On some platforms, inputs with large
+ * Converts this [IntX] to an [int]. On some platforms, inputs with large
* absolute values (i.e., > 2^52) may lose some of their low bits.
*/
int toInt();
/**
- * Converts an [intx] to 32 bits. Narrower values are sign extended and
+ * Converts an [IntX] to 32 bits. Narrower values are sign extended and
* wider values have their high bits truncated.
*/
- int32 toInt32();
+ Int32 toInt32();
/**
- * Converts an [intx] to 64 bits.
+ * Converts an [IntX] to 64 bits.
*/
- int64 toInt64();
+ Int64 toInt64();
/**
- * Returns the value of this [intx] as a decimal [String].
+ * Returns the value of this [IntX] as a decimal [String].
*/
String toString();
/**
- * Returns the value of this [intx] as a hexadecimal [String].
+ * Returns the value of this [IntX] as a hexadecimal [String].
*/
String toHexString();
/**
- * Returns the value of this [intx] as a [String] in the given radix.
+ * Returns the value of this [IntX] as a [String] in the given radix.
* [radix] must be an integer between 2 and 16, inclusive.
*/
String toRadixString(int radix);
diff --git a/pkg/fixnum/test/int_32_test.dart b/pkg/fixnum/test/int_32_test.dart
index 7e27d41..401f533 100644
--- a/pkg/fixnum/test/int_32_test.dart
+++ b/pkg/fixnum/test/int_32_test.dart
@@ -2,251 +2,251 @@
// 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 int32test;
+library Int32test;
import 'package:fixnum/fixnum.dart';
import 'package:unittest/unittest.dart';
void main() {
group("arithmetic operators", () {
- int32 n1 = new int32.fromInt(1234);
- int32 n2 = new int32.fromInt(9876);
- int32 n3 = new int32.fromInt(-1234);
- int32 n4 = new int32.fromInt(-9876);
- int32 n5 = new int32.fromInt(0x12345678);
- int32 n6 = new int32.fromInt(0x22222222);
+ Int32 n1 = new Int32.fromInt(1234);
+ Int32 n2 = new Int32.fromInt(9876);
+ Int32 n3 = new Int32.fromInt(-1234);
+ Int32 n4 = new Int32.fromInt(-9876);
+ Int32 n5 = new Int32.fromInt(0x12345678);
+ Int32 n6 = new Int32.fromInt(0x22222222);
test("+", () {
- expect(n1 + n2, new int32.fromInt(11110));
- expect(n3 + n2, new int32.fromInt(8642));
- expect(n3 + n4, new int32.fromInt(-11110));
- expect(int32.MAX_VALUE + 1, int32.MIN_VALUE);
- expect(() => new int32.fromInt(17) + null, throws);
+ expect(n1 + n2, new Int32.fromInt(11110));
+ expect(n3 + n2, new Int32.fromInt(8642));
+ expect(n3 + n4, new Int32.fromInt(-11110));
+ expect(Int32.MAX_VALUE + 1, Int32.MIN_VALUE);
+ expect(() => new Int32.fromInt(17) + null, throws);
});
test("-", () {
- expect(n1 - n2, new int32.fromInt(-8642));
- expect(n3 - n2, new int32.fromInt(-11110));
- expect(n3 - n4, new int32.fromInt(8642));
- expect(int32.MIN_VALUE - 1, int32.MAX_VALUE);
- expect(() => new int32.fromInt(17) - null, throws);
+ expect(n1 - n2, new Int32.fromInt(-8642));
+ expect(n3 - n2, new Int32.fromInt(-11110));
+ expect(n3 - n4, new Int32.fromInt(8642));
+ expect(Int32.MIN_VALUE - 1, Int32.MAX_VALUE);
+ expect(() => new Int32.fromInt(17) - null, throws);
});
test("unary -", () {
- expect(-n1, new int32.fromInt(-1234));
- expect(-int32.ZERO, int32.ZERO);
+ expect(-n1, new Int32.fromInt(-1234));
+ expect(-Int32.ZERO, Int32.ZERO);
});
test("*", () {
- expect(n1 * n2, new int32.fromInt(12186984));
- expect(n2 * n3, new int32.fromInt(-12186984));
- expect(n3 * n3, new int32.fromInt(1522756));
- expect(n3 * n2, new int32.fromInt(-12186984));
- expect(new int32.fromInt(0x12345678) * new int32.fromInt(0x22222222),
- new int32.fromInt(-899716112));
- expect((new int32.fromInt(123456789) * new int32.fromInt(987654321)),
- new int32.fromInt(-67153019));
- expect(new int32.fromInt(0x12345678) * new int64.fromInt(0x22222222),
- new int64.fromInts(0x026D60DC, 0xCA5F6BF0));
- expect((new int32.fromInt(123456789) * 987654321),
- new int32.fromInt(-67153019));
- expect(() => new int32.fromInt(17) * null, throws);
+ expect(n1 * n2, new Int32.fromInt(12186984));
+ expect(n2 * n3, new Int32.fromInt(-12186984));
+ expect(n3 * n3, new Int32.fromInt(1522756));
+ expect(n3 * n2, new Int32.fromInt(-12186984));
+ expect(new Int32.fromInt(0x12345678) * new Int32.fromInt(0x22222222),
+ new Int32.fromInt(-899716112));
+ expect((new Int32.fromInt(123456789) * new Int32.fromInt(987654321)),
+ new Int32.fromInt(-67153019));
+ expect(new Int32.fromInt(0x12345678) * new Int64.fromInt(0x22222222),
+ new Int64.fromInts(0x026D60DC, 0xCA5F6BF0));
+ expect((new Int32.fromInt(123456789) * 987654321),
+ new Int32.fromInt(-67153019));
+ expect(() => new Int32.fromInt(17) * null, throws);
});
test("~/", () {
- expect(new int32.fromInt(829893893) ~/ new int32.fromInt(1919),
- new int32.fromInt(432461));
- expect(new int32.fromInt(0x12345678) ~/ new int32.fromInt(0x22),
- new int32.fromInt(0x12345678 ~/ 0x22));
- expect(new int32.fromInt(829893893) ~/ new int64.fromInt(1919),
- new int32.fromInt(432461));
- expect(new int32.fromInt(0x12345678) ~/ new int64.fromInt(0x22),
- new int32.fromInt(0x12345678 ~/ 0x22));
- expect(new int32.fromInt(829893893) ~/ 1919, new int32.fromInt(432461));
- expect(() => new int32.fromInt(17) ~/ int32.ZERO, throws);
- expect(() => new int32.fromInt(17) ~/ null, throws);
+ expect(new Int32.fromInt(829893893) ~/ new Int32.fromInt(1919),
+ new Int32.fromInt(432461));
+ expect(new Int32.fromInt(0x12345678) ~/ new Int32.fromInt(0x22),
+ new Int32.fromInt(0x12345678 ~/ 0x22));
+ expect(new Int32.fromInt(829893893) ~/ new Int64.fromInt(1919),
+ new Int32.fromInt(432461));
+ expect(new Int32.fromInt(0x12345678) ~/ new Int64.fromInt(0x22),
+ new Int32.fromInt(0x12345678 ~/ 0x22));
+ expect(new Int32.fromInt(829893893) ~/ 1919, new Int32.fromInt(432461));
+ expect(() => new Int32.fromInt(17) ~/ Int32.ZERO, throws);
+ expect(() => new Int32.fromInt(17) ~/ null, throws);
});
test("%", () {
- expect(new int32.fromInt(0x12345678) % new int32.fromInt(0x22),
- new int32.fromInt(0x12345678 % 0x22));
- expect(new int32.fromInt(0x12345678) % new int64.fromInt(0x22),
- new int32.fromInt(0x12345678 % 0x22));
- expect(() => new int32.fromInt(17) % null, throws);
+ expect(new Int32.fromInt(0x12345678) % new Int32.fromInt(0x22),
+ new Int32.fromInt(0x12345678 % 0x22));
+ expect(new Int32.fromInt(0x12345678) % new Int64.fromInt(0x22),
+ new Int32.fromInt(0x12345678 % 0x22));
+ expect(() => new Int32.fromInt(17) % null, throws);
});
test("remainder", () {
- expect(new int32.fromInt(0x12345678).remainder(new int32.fromInt(0x22)),
- new int32.fromInt(0x12345678.remainder(0x22)));
- expect(new int32.fromInt(0x12345678).remainder(new int32.fromInt(-0x22)),
- new int32.fromInt(0x12345678.remainder(-0x22)));
- expect(new int32.fromInt(-0x12345678).remainder(new int32.fromInt(-0x22)),
- new int32.fromInt(-0x12345678.remainder(-0x22)));
- expect(new int32.fromInt(-0x12345678).remainder(new int32.fromInt(0x22)),
- new int32.fromInt(-0x12345678.remainder(0x22)));
- expect(new int32.fromInt(0x12345678).remainder(new int64.fromInt(0x22)),
- new int32.fromInt(0x12345678.remainder(0x22)));
- expect(() => new int32.fromInt(17).remainder(null), throws);
+ expect(new Int32.fromInt(0x12345678).remainder(new Int32.fromInt(0x22)),
+ new Int32.fromInt(0x12345678.remainder(0x22)));
+ expect(new Int32.fromInt(0x12345678).remainder(new Int32.fromInt(-0x22)),
+ new Int32.fromInt(0x12345678.remainder(-0x22)));
+ expect(new Int32.fromInt(-0x12345678).remainder(new Int32.fromInt(-0x22)),
+ new Int32.fromInt(-0x12345678.remainder(-0x22)));
+ expect(new Int32.fromInt(-0x12345678).remainder(new Int32.fromInt(0x22)),
+ new Int32.fromInt(-0x12345678.remainder(0x22)));
+ expect(new Int32.fromInt(0x12345678).remainder(new Int64.fromInt(0x22)),
+ new Int32.fromInt(0x12345678.remainder(0x22)));
+ expect(() => new Int32.fromInt(17).remainder(null), throws);
});
});
group("comparison operators", () {
test("<", () {
- expect(new int32.fromInt(17) < new int32.fromInt(18), true);
- expect(new int32.fromInt(17) < new int32.fromInt(17), false);
- expect(new int32.fromInt(17) < new int32.fromInt(16), false);
- expect(new int32.fromInt(17) < new int64.fromInt(18), true);
- expect(new int32.fromInt(17) < new int64.fromInt(17), false);
- expect(new int32.fromInt(17) < new int64.fromInt(16), false);
- expect(int32.MIN_VALUE < int32.MAX_VALUE, true);
- expect(int32.MAX_VALUE < int32.MIN_VALUE, false);
- expect(() => new int32.fromInt(17) < null, throws);
+ expect(new Int32.fromInt(17) < new Int32.fromInt(18), true);
+ expect(new Int32.fromInt(17) < new Int32.fromInt(17), false);
+ expect(new Int32.fromInt(17) < new Int32.fromInt(16), false);
+ expect(new Int32.fromInt(17) < new Int64.fromInt(18), true);
+ expect(new Int32.fromInt(17) < new Int64.fromInt(17), false);
+ expect(new Int32.fromInt(17) < new Int64.fromInt(16), false);
+ expect(Int32.MIN_VALUE < Int32.MAX_VALUE, true);
+ expect(Int32.MAX_VALUE < Int32.MIN_VALUE, false);
+ expect(() => new Int32.fromInt(17) < null, throws);
});
test("<=", () {
- expect(new int32.fromInt(17) <= new int32.fromInt(18), true);
- expect(new int32.fromInt(17) <= new int32.fromInt(17), true);
- expect(new int32.fromInt(17) <= new int32.fromInt(16), false);
- expect(new int32.fromInt(17) <= new int64.fromInt(18), true);
- expect(new int32.fromInt(17) <= new int64.fromInt(17), true);
- expect(new int32.fromInt(17) <= new int64.fromInt(16), false);
- expect(int32.MIN_VALUE <= int32.MAX_VALUE, true);
- expect(int32.MAX_VALUE <= int32.MIN_VALUE, false);
- expect(() => new int32.fromInt(17) <= null, throws);
+ expect(new Int32.fromInt(17) <= new Int32.fromInt(18), true);
+ expect(new Int32.fromInt(17) <= new Int32.fromInt(17), true);
+ expect(new Int32.fromInt(17) <= new Int32.fromInt(16), false);
+ expect(new Int32.fromInt(17) <= new Int64.fromInt(18), true);
+ expect(new Int32.fromInt(17) <= new Int64.fromInt(17), true);
+ expect(new Int32.fromInt(17) <= new Int64.fromInt(16), false);
+ expect(Int32.MIN_VALUE <= Int32.MAX_VALUE, true);
+ expect(Int32.MAX_VALUE <= Int32.MIN_VALUE, false);
+ expect(() => new Int32.fromInt(17) <= null, throws);
});
test("==", () {
- expect(new int32.fromInt(17) == new int32.fromInt(18), false);
- expect(new int32.fromInt(17) == new int32.fromInt(17), true);
- expect(new int32.fromInt(17) == new int32.fromInt(16), false);
- expect(new int32.fromInt(17) == new int64.fromInt(18), false);
- expect(new int32.fromInt(17) == new int64.fromInt(17), true);
- expect(new int32.fromInt(17) == new int64.fromInt(16), false);
- expect(int32.MIN_VALUE == int32.MAX_VALUE, false);
- expect(new int32.fromInt(17) == new Object(), false);
- expect(new int32.fromInt(17) == null, false);
+ expect(new Int32.fromInt(17) == new Int32.fromInt(18), false);
+ expect(new Int32.fromInt(17) == new Int32.fromInt(17), true);
+ expect(new Int32.fromInt(17) == new Int32.fromInt(16), false);
+ expect(new Int32.fromInt(17) == new Int64.fromInt(18), false);
+ expect(new Int32.fromInt(17) == new Int64.fromInt(17), true);
+ expect(new Int32.fromInt(17) == new Int64.fromInt(16), false);
+ expect(Int32.MIN_VALUE == Int32.MAX_VALUE, false);
+ expect(new Int32.fromInt(17) == new Object(), false);
+ expect(new Int32.fromInt(17) == null, false);
});
test(">=", () {
- expect(new int32.fromInt(17) >= new int32.fromInt(18), false);
- expect(new int32.fromInt(17) >= new int32.fromInt(17), true);
- expect(new int32.fromInt(17) >= new int32.fromInt(16), true);
- expect(new int32.fromInt(17) >= new int64.fromInt(18), false);
- expect(new int32.fromInt(17) >= new int64.fromInt(17), true);
- expect(new int32.fromInt(17) >= new int64.fromInt(16), true);
- expect(int32.MIN_VALUE >= int32.MAX_VALUE, false);
- expect(int32.MAX_VALUE >= int32.MIN_VALUE, true);
- expect(() => new int32.fromInt(17) >= null, throws);
+ expect(new Int32.fromInt(17) >= new Int32.fromInt(18), false);
+ expect(new Int32.fromInt(17) >= new Int32.fromInt(17), true);
+ expect(new Int32.fromInt(17) >= new Int32.fromInt(16), true);
+ expect(new Int32.fromInt(17) >= new Int64.fromInt(18), false);
+ expect(new Int32.fromInt(17) >= new Int64.fromInt(17), true);
+ expect(new Int32.fromInt(17) >= new Int64.fromInt(16), true);
+ expect(Int32.MIN_VALUE >= Int32.MAX_VALUE, false);
+ expect(Int32.MAX_VALUE >= Int32.MIN_VALUE, true);
+ expect(() => new Int32.fromInt(17) >= null, throws);
});
test(">", () {
- expect(new int32.fromInt(17) > new int32.fromInt(18), false);
- expect(new int32.fromInt(17) > new int32.fromInt(17), false);
- expect(new int32.fromInt(17) > new int32.fromInt(16), true);
- expect(new int32.fromInt(17) > new int64.fromInt(18), false);
- expect(new int32.fromInt(17) > new int64.fromInt(17), false);
- expect(new int32.fromInt(17) > new int64.fromInt(16), true);
- expect(int32.MIN_VALUE > int32.MAX_VALUE, false);
- expect(int32.MAX_VALUE > int32.MIN_VALUE, true);
- expect(() => new int32.fromInt(17) > null, throws);
+ expect(new Int32.fromInt(17) > new Int32.fromInt(18), false);
+ expect(new Int32.fromInt(17) > new Int32.fromInt(17), false);
+ expect(new Int32.fromInt(17) > new Int32.fromInt(16), true);
+ expect(new Int32.fromInt(17) > new Int64.fromInt(18), false);
+ expect(new Int32.fromInt(17) > new Int64.fromInt(17), false);
+ expect(new Int32.fromInt(17) > new Int64.fromInt(16), true);
+ expect(Int32.MIN_VALUE > Int32.MAX_VALUE, false);
+ expect(Int32.MAX_VALUE > Int32.MIN_VALUE, true);
+ expect(() => new Int32.fromInt(17) > null, throws);
});
});
group("bitwise operators", () {
test("&", () {
- expect(new int32.fromInt(0x12345678) & new int32.fromInt(0x22222222),
- new int32.fromInt(0x12345678 & 0x22222222));
- expect(new int32.fromInt(0x12345678) & new int64.fromInt(0x22222222),
- new int64.fromInt(0x12345678 & 0x22222222));
- expect(() => new int32.fromInt(17) & null, throwsArgumentError);
+ expect(new Int32.fromInt(0x12345678) & new Int32.fromInt(0x22222222),
+ new Int32.fromInt(0x12345678 & 0x22222222));
+ expect(new Int32.fromInt(0x12345678) & new Int64.fromInt(0x22222222),
+ new Int64.fromInt(0x12345678 & 0x22222222));
+ expect(() => new Int32.fromInt(17) & null, throwsArgumentError);
});
test("|", () {
- expect(new int32.fromInt(0x12345678) | new int32.fromInt(0x22222222),
- new int32.fromInt(0x12345678 | 0x22222222));
- expect(new int32.fromInt(0x12345678) | new int64.fromInt(0x22222222),
- new int64.fromInt(0x12345678 | 0x22222222));
- expect(() => new int32.fromInt(17) | null, throws);
+ expect(new Int32.fromInt(0x12345678) | new Int32.fromInt(0x22222222),
+ new Int32.fromInt(0x12345678 | 0x22222222));
+ expect(new Int32.fromInt(0x12345678) | new Int64.fromInt(0x22222222),
+ new Int64.fromInt(0x12345678 | 0x22222222));
+ expect(() => new Int32.fromInt(17) | null, throws);
});
test("^", () {
- expect(new int32.fromInt(0x12345678) ^ new int32.fromInt(0x22222222),
- new int32.fromInt(0x12345678 ^ 0x22222222));
- expect(new int32.fromInt(0x12345678) ^ new int64.fromInt(0x22222222),
- new int64.fromInt(0x12345678 ^ 0x22222222));
- expect(() => new int32.fromInt(17) ^ null, throws);
+ expect(new Int32.fromInt(0x12345678) ^ new Int32.fromInt(0x22222222),
+ new Int32.fromInt(0x12345678 ^ 0x22222222));
+ expect(new Int32.fromInt(0x12345678) ^ new Int64.fromInt(0x22222222),
+ new Int64.fromInt(0x12345678 ^ 0x22222222));
+ expect(() => new Int32.fromInt(17) ^ null, throws);
});
test("~", () {
- expect(~(new int32.fromInt(0x12345678)), new int32.fromInt(~0x12345678));
- expect(-(new int32.fromInt(0x12345678)), new int64.fromInt(-0x12345678));
+ expect(~(new Int32.fromInt(0x12345678)), new Int32.fromInt(~0x12345678));
+ expect(-(new Int32.fromInt(0x12345678)), new Int64.fromInt(-0x12345678));
});
});
group("bitshift operators", () {
test("<<", () {
- expect(new int32.fromInt(0x12345678) << 7,
- new int32.fromInt(0x12345678 << 7));
- expect(() => new int32.fromInt(17) << -1, throwsArgumentError);
- expect(() => new int32.fromInt(17) << null, throws);
+ expect(new Int32.fromInt(0x12345678) << 7,
+ new Int32.fromInt(0x12345678 << 7));
+ expect(() => new Int32.fromInt(17) << -1, throwsArgumentError);
+ expect(() => new Int32.fromInt(17) << null, throws);
});
test(">>", () {
- expect(new int32.fromInt(0x12345678) >> 7,
- new int32.fromInt(0x12345678 >> 7));
- expect(() => new int32.fromInt(17) >> -1, throwsArgumentError);
- expect(() => new int32.fromInt(17) >> null, throws);
+ expect(new Int32.fromInt(0x12345678) >> 7,
+ new Int32.fromInt(0x12345678 >> 7));
+ expect(() => new Int32.fromInt(17) >> -1, throwsArgumentError);
+ expect(() => new Int32.fromInt(17) >> null, throws);
});
test("shiftRightUnsigned", () {
- expect(new int32.fromInt(0x12345678).shiftRightUnsigned(7),
- new int32.fromInt(0x12345678 >> 7));
- expect(() => (new int32.fromInt(17).shiftRightUnsigned(-1)),
+ expect(new Int32.fromInt(0x12345678).shiftRightUnsigned(7),
+ new Int32.fromInt(0x12345678 >> 7));
+ expect(() => (new Int32.fromInt(17).shiftRightUnsigned(-1)),
throwsArgumentError);
- expect(() => (new int32.fromInt(17).shiftRightUnsigned(null)), throws);
+ expect(() => (new Int32.fromInt(17).shiftRightUnsigned(null)), throws);
});
});
group("type conversions", () {
- expect(new int32.fromInt(17).toInt(), 17);
- expect(new int32.fromInt(-17).toInt(), -17);
- expect(new int32.fromInt(17).toInt32(), new int32.fromInt(17));
- expect(new int32.fromInt(-17).toInt32(), new int32.fromInt(-17));
- expect(new int32.fromInt(17).toInt64(), new int64.fromInt(17));
- expect(new int32.fromInt(-17).toInt64(), new int64.fromInt(-17));
+ expect(new Int32.fromInt(17).toInt(), 17);
+ expect(new Int32.fromInt(-17).toInt(), -17);
+ expect(new Int32.fromInt(17).toInt32(), new Int32.fromInt(17));
+ expect(new Int32.fromInt(-17).toInt32(), new Int32.fromInt(-17));
+ expect(new Int32.fromInt(17).toInt64(), new Int64.fromInt(17));
+ expect(new Int32.fromInt(-17).toInt64(), new Int64.fromInt(-17));
});
group("string representation", () {
test("toString", () {
- expect(new int32.fromInt(0).toString(), "0");
- expect(new int32.fromInt(1).toString(), "1");
- expect(new int32.fromInt(-1).toString(), "-1");
- expect(new int32.fromInt(1000).toString(), "1000");
- expect(new int32.fromInt(-1000).toString(), "-1000");
- expect(new int32.fromInt(123456789).toString(), "123456789");
- expect(new int32.fromInt(2147483647).toString(), "2147483647");
- expect(new int32.fromInt(2147483648).toString(), "-2147483648");
- expect(new int32.fromInt(2147483649).toString(), "-2147483647");
- expect(new int32.fromInt(2147483650).toString(), "-2147483646");
- expect(new int32.fromInt(-2147483648).toString(), "-2147483648");
- expect(new int32.fromInt(-2147483649).toString(), "2147483647");
- expect(new int32.fromInt(-2147483650).toString(), "2147483646");
+ expect(new Int32.fromInt(0).toString(), "0");
+ expect(new Int32.fromInt(1).toString(), "1");
+ expect(new Int32.fromInt(-1).toString(), "-1");
+ expect(new Int32.fromInt(1000).toString(), "1000");
+ expect(new Int32.fromInt(-1000).toString(), "-1000");
+ expect(new Int32.fromInt(123456789).toString(), "123456789");
+ expect(new Int32.fromInt(2147483647).toString(), "2147483647");
+ expect(new Int32.fromInt(2147483648).toString(), "-2147483648");
+ expect(new Int32.fromInt(2147483649).toString(), "-2147483647");
+ expect(new Int32.fromInt(2147483650).toString(), "-2147483646");
+ expect(new Int32.fromInt(-2147483648).toString(), "-2147483648");
+ expect(new Int32.fromInt(-2147483649).toString(), "2147483647");
+ expect(new Int32.fromInt(-2147483650).toString(), "2147483646");
});
});
group("toHexString", () {
test("returns hexadecimal string representation", () {
- expect(new int32.fromInt(-1).toHexString(), "-1");
- expect((new int32.fromInt(-1) >> 8).toHexString(), "-1");
- expect((new int32.fromInt(-1) << 8).toHexString(), "-100");
- expect(new int32.fromInt(123456789).toHexString(), "75bcd15");
- expect(new int32.fromInt(-1).shiftRightUnsigned(8).toHexString(),
+ expect(new Int32.fromInt(-1).toHexString(), "-1");
+ expect((new Int32.fromInt(-1) >> 8).toHexString(), "-1");
+ expect((new Int32.fromInt(-1) << 8).toHexString(), "-100");
+ expect(new Int32.fromInt(123456789).toHexString(), "75bcd15");
+ expect(new Int32.fromInt(-1).shiftRightUnsigned(8).toHexString(),
"ffffff");
});
});
group("toRadixString", () {
test("returns base n string representation", () {
- expect(new int32.fromInt(123456789).toRadixString(5), "223101104124");
+ expect(new Int32.fromInt(123456789).toRadixString(5), "223101104124");
});
});
}
diff --git a/pkg/fixnum/test/int_64_test.dart b/pkg/fixnum/test/int_64_test.dart
index 4ff8e1c..545de3c 100644
--- a/pkg/fixnum/test/int_64_test.dart
+++ b/pkg/fixnum/test/int_64_test.dart
@@ -8,592 +8,592 @@
void main() {
group("arithmetic operators", () {
- int64 n1 = new int64.fromInt(1234);
- int64 n2 = new int64.fromInt(9876);
- int64 n3 = new int64.fromInt(-1234);
- int64 n4 = new int64.fromInt(-9876);
- int64 n5 = new int64.fromInts(0x12345678, 0xabcdabcd);
- int64 n6 = new int64.fromInts(0x77773333, 0x22224444);
+ Int64 n1 = new Int64.fromInt(1234);
+ Int64 n2 = new Int64.fromInt(9876);
+ Int64 n3 = new Int64.fromInt(-1234);
+ Int64 n4 = new Int64.fromInt(-9876);
+ Int64 n5 = new Int64.fromInts(0x12345678, 0xabcdabcd);
+ Int64 n6 = new Int64.fromInts(0x77773333, 0x22224444);
test("+", () {
- expect(n1 + n2, new int64.fromInt(11110));
- expect(n3 + n2, new int64.fromInt(8642));
- expect(n3 + n4, new int64.fromInt(-11110));
- expect(n5 + n6, new int64.fromInts(0x89ab89ab, 0xcdeff011));
- expect(int64.MAX_VALUE + 1, int64.MIN_VALUE);
+ expect(n1 + n2, new Int64.fromInt(11110));
+ expect(n3 + n2, new Int64.fromInt(8642));
+ expect(n3 + n4, new Int64.fromInt(-11110));
+ expect(n5 + n6, new Int64.fromInts(0x89ab89ab, 0xcdeff011));
+ expect(Int64.MAX_VALUE + 1, Int64.MIN_VALUE);
});
test("-", () {
- expect(n1 - n2, new int64.fromInt(-8642));
- expect(n3 - n2, new int64.fromInt(-11110));
- expect(n3 - n4, new int64.fromInt(8642));
- expect(n5 - n6, new int64.fromInts(0x9abd2345, 0x89ab6789));
- expect(int64.MIN_VALUE - 1, int64.MAX_VALUE);
+ expect(n1 - n2, new Int64.fromInt(-8642));
+ expect(n3 - n2, new Int64.fromInt(-11110));
+ expect(n3 - n4, new Int64.fromInt(8642));
+ expect(n5 - n6, new Int64.fromInts(0x9abd2345, 0x89ab6789));
+ expect(Int64.MIN_VALUE - 1, Int64.MAX_VALUE);
});
test("unary -", () {
- expect(-n1, new int64.fromInt(-1234));
- expect(-int64.ZERO, int64.ZERO);
+ expect(-n1, new Int64.fromInt(-1234));
+ expect(-Int64.ZERO, Int64.ZERO);
});
test("*", () {
- expect(new int64.fromInt(1111) * new int64.fromInt(3),
- new int64.fromInt(3333));
- expect(new int64.fromInt(1111) * new int64.fromInt(-3),
- new int64.fromInt(-3333));
- expect(new int64.fromInt(-1111) * new int64.fromInt(3),
- new int64.fromInt(-3333));
- expect(new int64.fromInt(-1111) * new int64.fromInt(-3),
- new int64.fromInt(3333));
- expect(new int64.fromInt(100) * new int64.fromInt(0),
- new int64.fromInt(0));
+ expect(new Int64.fromInt(1111) * new Int64.fromInt(3),
+ new Int64.fromInt(3333));
+ expect(new Int64.fromInt(1111) * new Int64.fromInt(-3),
+ new Int64.fromInt(-3333));
+ expect(new Int64.fromInt(-1111) * new Int64.fromInt(3),
+ new Int64.fromInt(-3333));
+ expect(new Int64.fromInt(-1111) * new Int64.fromInt(-3),
+ new Int64.fromInt(3333));
+ expect(new Int64.fromInt(100) * new Int64.fromInt(0),
+ new Int64.fromInt(0));
- expect(new int64.fromInts(0x12345678, 0x12345678) *
- new int64.fromInts(0x1234, 0x12345678),
- new int64.fromInts(0x7ff63f7c, 0x1df4d840));
- expect(new int64.fromInts(0xf2345678, 0x12345678) *
- new int64.fromInts(0x1234, 0x12345678),
- new int64.fromInts(0x7ff63f7c, 0x1df4d840));
- expect(new int64.fromInts(0xf2345678, 0x12345678) *
- new int64.fromInts(0xffff1234, 0x12345678),
- new int64.fromInts(0x297e3f7c, 0x1df4d840));
+ expect(new Int64.fromInts(0x12345678, 0x12345678) *
+ new Int64.fromInts(0x1234, 0x12345678),
+ new Int64.fromInts(0x7ff63f7c, 0x1df4d840));
+ expect(new Int64.fromInts(0xf2345678, 0x12345678) *
+ new Int64.fromInts(0x1234, 0x12345678),
+ new Int64.fromInts(0x7ff63f7c, 0x1df4d840));
+ expect(new Int64.fromInts(0xf2345678, 0x12345678) *
+ new Int64.fromInts(0xffff1234, 0x12345678),
+ new Int64.fromInts(0x297e3f7c, 0x1df4d840));
- // RHS int32
- expect((new int64.fromInt(123456789) * new int32.fromInt(987654321)),
- new int64.fromInts(0x1b13114, 0xfbff5385));
- expect((new int64.fromInt(123456789) * new int32.fromInt(987654321)),
- new int64.fromInts(0x1b13114, 0xfbff5385));
+ // RHS Int32
+ expect((new Int64.fromInt(123456789) * new Int32.fromInt(987654321)),
+ new Int64.fromInts(0x1b13114, 0xfbff5385));
+ expect((new Int64.fromInt(123456789) * new Int32.fromInt(987654321)),
+ new Int64.fromInts(0x1b13114, 0xfbff5385));
// Wraparound
- expect((new int64.fromInt(123456789) * new int64.fromInt(987654321)),
- new int64.fromInts(0x1b13114, 0xfbff5385));
+ expect((new Int64.fromInt(123456789) * new Int64.fromInt(987654321)),
+ new Int64.fromInts(0x1b13114, 0xfbff5385));
- expect(int64.MIN_VALUE * new int64.fromInt(2), new int64.fromInt(0));
- expect(int64.MIN_VALUE * new int64.fromInt(1), int64.MIN_VALUE);
- expect(int64.MIN_VALUE * new int64.fromInt(-1), int64.MIN_VALUE);
+ expect(Int64.MIN_VALUE * new Int64.fromInt(2), new Int64.fromInt(0));
+ expect(Int64.MIN_VALUE * new Int64.fromInt(1), Int64.MIN_VALUE);
+ expect(Int64.MIN_VALUE * new Int64.fromInt(-1), Int64.MIN_VALUE);
});
test("~/", () {
- int64 deadBeef = new int64.fromInts(0xDEADBEEF, 0xDEADBEEF);
- int64 ten = new int64.fromInt(10);
+ Int64 deadBeef = new Int64.fromInts(0xDEADBEEF, 0xDEADBEEF);
+ Int64 ten = new Int64.fromInt(10);
- expect(deadBeef ~/ ten, new int64.fromInts(0xfcaaf97e, 0x63115fe5));
- expect(int64.ONE ~/ int64.TWO, int64.ZERO);
- expect(int64.MAX_VALUE ~/ int64.TWO,
- new int64.fromInts(0x3fffffff, 0xffffffff));
- expect(int64.ZERO ~/ new int64.fromInt(1000), int64.ZERO);
- expect(int64.MIN_VALUE ~/ int64.MIN_VALUE, int64.ONE);
- expect(new int64.fromInt(1000) ~/ int64.MIN_VALUE, int64.ZERO);
- expect(int64.MIN_VALUE ~/ new int64.fromInt(8192),
- new int64.fromInt(-1125899906842624));
- expect(int64.MIN_VALUE ~/ new int64.fromInt(8193),
- new int64.fromInt(-1125762484664320));
- expect(new int64.fromInt(-1000) ~/ new int64.fromInt(8192), int64.ZERO);
- expect(new int64.fromInt(-1000) ~/ new int64.fromInt(8193), int64.ZERO);
- expect(new int64.fromInt(-1000000000) ~/ new int64.fromInt(8192),
- new int64.fromInt(-122070));
- expect(new int64.fromInt(-1000000000) ~/ new int64.fromInt(8193),
- new int64.fromInt(-122055));
- expect(new int64.fromInt(1000000000) ~/ new int64.fromInt(8192),
- new int64.fromInt(122070));
- expect(new int64.fromInt(1000000000) ~/ new int64.fromInt(8193),
- new int64.fromInt(122055));
- expect(int64.MAX_VALUE ~/ new int64.fromInts(0x00000000, 0x00000400),
- new int64.fromInts(0x1fffff, 0xffffffff));
- expect(int64.MAX_VALUE ~/ new int64.fromInts(0x00000000, 0x00040000),
- new int64.fromInts(0x1fff, 0xffffffff));
- expect(int64.MAX_VALUE ~/ new int64.fromInts(0x00000000, 0x04000000),
- new int64.fromInts(0x1f, 0xffffffff));
- expect(int64.MAX_VALUE ~/ new int64.fromInts(0x00000004, 0x00000000),
- new int64.fromInt(536870911));
- expect(int64.MAX_VALUE ~/ new int64.fromInts(0x00000400, 0x00000000),
- new int64.fromInt(2097151));
- expect(int64.MAX_VALUE ~/ new int64.fromInts(0x00040000, 0x00000000),
- new int64.fromInt(8191));
- expect(int64.MAX_VALUE ~/ new int64.fromInts(0x04000000, 0x00000000),
- new int64.fromInt(31));
- expect(int64.MAX_VALUE ~/ new int64.fromInts(0x00000000, 0x00000300),
- new int64.fromInts(0x2AAAAA, 0xAAAAAAAA));
- expect(int64.MAX_VALUE ~/ new int64.fromInts(0x00000000, 0x30000000),
- new int64.fromInts(0x2, 0xAAAAAAAA));
- expect(int64.MAX_VALUE ~/ new int64.fromInts(0x00300000, 0x00000000),
- new int64.fromInt(0x2AA));
- expect(int64.MAX_VALUE ~/ new int64.fromInt(0x123456),
- new int64.fromInts(0x708, 0x002E9501));
- expect(int64.MAX_VALUE % new int64.fromInt(0x123456),
- new int64.fromInt(0x3BDA9));
- expect(new int64.fromInt(5) ~/ new int64.fromInt(5),
- new int64.fromInt(1));
- expect(new int64.fromInt(1000) ~/ new int64.fromInt(3),
- new int64.fromInt(333));
- expect(new int64.fromInt(1000) ~/ new int64.fromInt(-3),
- new int64.fromInt(-333));
- expect(new int64.fromInt(-1000) ~/ new int64.fromInt(3),
- new int64.fromInt(-333));
- expect(new int64.fromInt(-1000) ~/ new int64.fromInt(-3),
- new int64.fromInt(333));
- expect(new int64.fromInt(3) ~/ new int64.fromInt(1000),
- new int64.fromInt(0));
- expect(new int64.fromInts( 0x12345678, 0x12345678) ~/
- new int64.fromInts(0x0, 0x123),
- new int64.fromInts(0x1003d0, 0xe84f5ae8));
- expect(new int64.fromInts(0x12345678, 0x12345678) ~/
- new int64.fromInts(0x1234, 0x12345678),
- new int64.fromInts(0x0, 0x10003));
- expect(new int64.fromInts(0xf2345678, 0x12345678) ~/
- new int64.fromInts(0x1234, 0x12345678),
- new int64.fromInts(0xffffffff, 0xffff3dfe));
- expect(new int64.fromInts(0xf2345678, 0x12345678) ~/
- new int64.fromInts(0xffff1234, 0x12345678),
- new int64.fromInts(0x0, 0xeda));
- expect(new int64.fromInt(829893893) ~/ new int32.fromInt(1919),
- new int32.fromInt(432461));
- expect(new int64.fromInt(829893893) ~/ new int64.fromInt(1919),
- new int32.fromInt(432461));
- expect(new int64.fromInt(829893893) ~/ 1919,
- new int32.fromInt(432461));
- expect(() => new int64.fromInt(1) ~/ new int64.fromInt(0),
+ expect(deadBeef ~/ ten, new Int64.fromInts(0xfcaaf97e, 0x63115fe5));
+ expect(Int64.ONE ~/ Int64.TWO, Int64.ZERO);
+ expect(Int64.MAX_VALUE ~/ Int64.TWO,
+ new Int64.fromInts(0x3fffffff, 0xffffffff));
+ expect(Int64.ZERO ~/ new Int64.fromInt(1000), Int64.ZERO);
+ expect(Int64.MIN_VALUE ~/ Int64.MIN_VALUE, Int64.ONE);
+ expect(new Int64.fromInt(1000) ~/ Int64.MIN_VALUE, Int64.ZERO);
+ expect(Int64.MIN_VALUE ~/ new Int64.fromInt(8192),
+ new Int64.fromInt(-1125899906842624));
+ expect(Int64.MIN_VALUE ~/ new Int64.fromInt(8193),
+ new Int64.fromInt(-1125762484664320));
+ expect(new Int64.fromInt(-1000) ~/ new Int64.fromInt(8192), Int64.ZERO);
+ expect(new Int64.fromInt(-1000) ~/ new Int64.fromInt(8193), Int64.ZERO);
+ expect(new Int64.fromInt(-1000000000) ~/ new Int64.fromInt(8192),
+ new Int64.fromInt(-122070));
+ expect(new Int64.fromInt(-1000000000) ~/ new Int64.fromInt(8193),
+ new Int64.fromInt(-122055));
+ expect(new Int64.fromInt(1000000000) ~/ new Int64.fromInt(8192),
+ new Int64.fromInt(122070));
+ expect(new Int64.fromInt(1000000000) ~/ new Int64.fromInt(8193),
+ new Int64.fromInt(122055));
+ expect(Int64.MAX_VALUE ~/ new Int64.fromInts(0x00000000, 0x00000400),
+ new Int64.fromInts(0x1fffff, 0xffffffff));
+ expect(Int64.MAX_VALUE ~/ new Int64.fromInts(0x00000000, 0x00040000),
+ new Int64.fromInts(0x1fff, 0xffffffff));
+ expect(Int64.MAX_VALUE ~/ new Int64.fromInts(0x00000000, 0x04000000),
+ new Int64.fromInts(0x1f, 0xffffffff));
+ expect(Int64.MAX_VALUE ~/ new Int64.fromInts(0x00000004, 0x00000000),
+ new Int64.fromInt(536870911));
+ expect(Int64.MAX_VALUE ~/ new Int64.fromInts(0x00000400, 0x00000000),
+ new Int64.fromInt(2097151));
+ expect(Int64.MAX_VALUE ~/ new Int64.fromInts(0x00040000, 0x00000000),
+ new Int64.fromInt(8191));
+ expect(Int64.MAX_VALUE ~/ new Int64.fromInts(0x04000000, 0x00000000),
+ new Int64.fromInt(31));
+ expect(Int64.MAX_VALUE ~/ new Int64.fromInts(0x00000000, 0x00000300),
+ new Int64.fromInts(0x2AAAAA, 0xAAAAAAAA));
+ expect(Int64.MAX_VALUE ~/ new Int64.fromInts(0x00000000, 0x30000000),
+ new Int64.fromInts(0x2, 0xAAAAAAAA));
+ expect(Int64.MAX_VALUE ~/ new Int64.fromInts(0x00300000, 0x00000000),
+ new Int64.fromInt(0x2AA));
+ expect(Int64.MAX_VALUE ~/ new Int64.fromInt(0x123456),
+ new Int64.fromInts(0x708, 0x002E9501));
+ expect(Int64.MAX_VALUE % new Int64.fromInt(0x123456),
+ new Int64.fromInt(0x3BDA9));
+ expect(new Int64.fromInt(5) ~/ new Int64.fromInt(5),
+ new Int64.fromInt(1));
+ expect(new Int64.fromInt(1000) ~/ new Int64.fromInt(3),
+ new Int64.fromInt(333));
+ expect(new Int64.fromInt(1000) ~/ new Int64.fromInt(-3),
+ new Int64.fromInt(-333));
+ expect(new Int64.fromInt(-1000) ~/ new Int64.fromInt(3),
+ new Int64.fromInt(-333));
+ expect(new Int64.fromInt(-1000) ~/ new Int64.fromInt(-3),
+ new Int64.fromInt(333));
+ expect(new Int64.fromInt(3) ~/ new Int64.fromInt(1000),
+ new Int64.fromInt(0));
+ expect(new Int64.fromInts( 0x12345678, 0x12345678) ~/
+ new Int64.fromInts(0x0, 0x123),
+ new Int64.fromInts(0x1003d0, 0xe84f5ae8));
+ expect(new Int64.fromInts(0x12345678, 0x12345678) ~/
+ new Int64.fromInts(0x1234, 0x12345678),
+ new Int64.fromInts(0x0, 0x10003));
+ expect(new Int64.fromInts(0xf2345678, 0x12345678) ~/
+ new Int64.fromInts(0x1234, 0x12345678),
+ new Int64.fromInts(0xffffffff, 0xffff3dfe));
+ expect(new Int64.fromInts(0xf2345678, 0x12345678) ~/
+ new Int64.fromInts(0xffff1234, 0x12345678),
+ new Int64.fromInts(0x0, 0xeda));
+ expect(new Int64.fromInt(829893893) ~/ new Int32.fromInt(1919),
+ new Int32.fromInt(432461));
+ expect(new Int64.fromInt(829893893) ~/ new Int64.fromInt(1919),
+ new Int32.fromInt(432461));
+ expect(new Int64.fromInt(829893893) ~/ 1919,
+ new Int32.fromInt(432461));
+ expect(() => new Int64.fromInt(1) ~/ new Int64.fromInt(0),
throwsA(new isInstanceOf<IntegerDivisionByZeroException>()));
- expect(int64.MIN_VALUE ~/ new int64.fromInt(2),
- new int64.fromInts(0xc0000000, 0x00000000));
- expect(int64.MIN_VALUE ~/ new int64.fromInt(1), int64.MIN_VALUE);
- expect(int64.MIN_VALUE ~/ new int64.fromInt(-1), int64.MIN_VALUE);
- expect(() => new int64.fromInt(17) ~/ int64.ZERO, throws);
- expect(() => new int64.fromInt(17) ~/ null, throwsArgumentError);
+ expect(Int64.MIN_VALUE ~/ new Int64.fromInt(2),
+ new Int64.fromInts(0xc0000000, 0x00000000));
+ expect(Int64.MIN_VALUE ~/ new Int64.fromInt(1), Int64.MIN_VALUE);
+ expect(Int64.MIN_VALUE ~/ new Int64.fromInt(-1), Int64.MIN_VALUE);
+ expect(() => new Int64.fromInt(17) ~/ Int64.ZERO, throws);
+ expect(() => new Int64.fromInt(17) ~/ null, throwsArgumentError);
});
test("%", () {
// Define % as Euclidean mod, with positive result for all arguments
- expect(int64.ZERO % new int64.fromInt(1000), new int64.fromInt(0));
- expect(int64.MIN_VALUE % int64.MIN_VALUE, new int64.fromInt(0));
- expect(new int64.fromInt(1000) % int64.MIN_VALUE,
- new int64.fromInt(1000));
- expect(int64.MIN_VALUE % new int64.fromInt(8192), new int64.fromInt(0));
- expect(int64.MIN_VALUE % new int64.fromInt(8193),
- new int64.fromInt(6145));
- expect(new int64.fromInt(-1000) % new int64.fromInt(8192),
- new int64.fromInt(7192));
- expect(new int64.fromInt(-1000) % new int64.fromInt(8193),
- new int64.fromInt(7193));
- expect(new int64.fromInt(-1000000000) % new int64.fromInt(8192),
- new int64.fromInt(5632));
- expect(new int64.fromInt(-1000000000) % new int64.fromInt(8193),
- new int64.fromInt(4808));
- expect(new int64.fromInt(1000000000) % new int64.fromInt(8192),
- new int64.fromInt(2560));
- expect(new int64.fromInt(1000000000) % new int64.fromInt(8193),
- new int64.fromInt(3385));
- expect(int64.MAX_VALUE % new int64.fromInts(0x00000000, 0x00000400),
- new int64.fromInts(0x0, 0x3ff));
- expect(int64.MAX_VALUE % new int64.fromInts(0x00000000, 0x00040000),
- new int64.fromInts(0x0, 0x3ffff));
- expect(int64.MAX_VALUE % new int64.fromInts(0x00000000, 0x04000000),
- new int64.fromInts(0x0, 0x3ffffff));
- expect(int64.MAX_VALUE % new int64.fromInts(0x00000004, 0x00000000),
- new int64.fromInts(0x3, 0xffffffff));
- expect(int64.MAX_VALUE % new int64.fromInts(0x00000400, 0x00000000),
- new int64.fromInts(0x3ff, 0xffffffff));
- expect(int64.MAX_VALUE % new int64.fromInts(0x00040000, 0x00000000),
- new int64.fromInts(0x3ffff, 0xffffffff));
- expect(int64.MAX_VALUE % new int64.fromInts(0x04000000, 0x00000000),
- new int64.fromInts(0x3ffffff, 0xffffffff));
- expect(new int64.fromInt(0x12345678).remainder(new int64.fromInt(0x22)),
- new int64.fromInt(0x12345678.remainder(0x22)));
- expect(new int64.fromInt(0x12345678).remainder(new int64.fromInt(-0x22)),
- new int64.fromInt(0x12345678.remainder(-0x22)));
- expect(new int64.fromInt(-0x12345678).remainder(new int64.fromInt(-0x22)),
- new int64.fromInt(-0x12345678.remainder(-0x22)));
- expect(new int64.fromInt(-0x12345678).remainder(new int64.fromInt(0x22)),
- new int64.fromInt(-0x12345678.remainder(0x22)));
- expect(new int32.fromInt(0x12345678).remainder(new int64.fromInt(0x22)),
- new int64.fromInt(0x12345678.remainder(0x22)));
+ expect(Int64.ZERO % new Int64.fromInt(1000), new Int64.fromInt(0));
+ expect(Int64.MIN_VALUE % Int64.MIN_VALUE, new Int64.fromInt(0));
+ expect(new Int64.fromInt(1000) % Int64.MIN_VALUE,
+ new Int64.fromInt(1000));
+ expect(Int64.MIN_VALUE % new Int64.fromInt(8192), new Int64.fromInt(0));
+ expect(Int64.MIN_VALUE % new Int64.fromInt(8193),
+ new Int64.fromInt(6145));
+ expect(new Int64.fromInt(-1000) % new Int64.fromInt(8192),
+ new Int64.fromInt(7192));
+ expect(new Int64.fromInt(-1000) % new Int64.fromInt(8193),
+ new Int64.fromInt(7193));
+ expect(new Int64.fromInt(-1000000000) % new Int64.fromInt(8192),
+ new Int64.fromInt(5632));
+ expect(new Int64.fromInt(-1000000000) % new Int64.fromInt(8193),
+ new Int64.fromInt(4808));
+ expect(new Int64.fromInt(1000000000) % new Int64.fromInt(8192),
+ new Int64.fromInt(2560));
+ expect(new Int64.fromInt(1000000000) % new Int64.fromInt(8193),
+ new Int64.fromInt(3385));
+ expect(Int64.MAX_VALUE % new Int64.fromInts(0x00000000, 0x00000400),
+ new Int64.fromInts(0x0, 0x3ff));
+ expect(Int64.MAX_VALUE % new Int64.fromInts(0x00000000, 0x00040000),
+ new Int64.fromInts(0x0, 0x3ffff));
+ expect(Int64.MAX_VALUE % new Int64.fromInts(0x00000000, 0x04000000),
+ new Int64.fromInts(0x0, 0x3ffffff));
+ expect(Int64.MAX_VALUE % new Int64.fromInts(0x00000004, 0x00000000),
+ new Int64.fromInts(0x3, 0xffffffff));
+ expect(Int64.MAX_VALUE % new Int64.fromInts(0x00000400, 0x00000000),
+ new Int64.fromInts(0x3ff, 0xffffffff));
+ expect(Int64.MAX_VALUE % new Int64.fromInts(0x00040000, 0x00000000),
+ new Int64.fromInts(0x3ffff, 0xffffffff));
+ expect(Int64.MAX_VALUE % new Int64.fromInts(0x04000000, 0x00000000),
+ new Int64.fromInts(0x3ffffff, 0xffffffff));
+ expect(new Int64.fromInt(0x12345678).remainder(new Int64.fromInt(0x22)),
+ new Int64.fromInt(0x12345678.remainder(0x22)));
+ expect(new Int64.fromInt(0x12345678).remainder(new Int64.fromInt(-0x22)),
+ new Int64.fromInt(0x12345678.remainder(-0x22)));
+ expect(new Int64.fromInt(-0x12345678).remainder(new Int64.fromInt(-0x22)),
+ new Int64.fromInt(-0x12345678.remainder(-0x22)));
+ expect(new Int64.fromInt(-0x12345678).remainder(new Int64.fromInt(0x22)),
+ new Int64.fromInt(-0x12345678.remainder(0x22)));
+ expect(new Int32.fromInt(0x12345678).remainder(new Int64.fromInt(0x22)),
+ new Int64.fromInt(0x12345678.remainder(0x22)));
});
});
group("comparison operators", () {
- int64 largeNeg = new int64.fromInts(0x82341234, 0x0);
- int64 largePos = new int64.fromInts(0x12341234, 0x0);
- int64 largePosPlusOne = largePos + new int64.fromInt(1);
+ Int64 largeNeg = new Int64.fromInts(0x82341234, 0x0);
+ Int64 largePos = new Int64.fromInts(0x12341234, 0x0);
+ Int64 largePosPlusOne = largePos + new Int64.fromInt(1);
test("<", () {
- expect(new int64.fromInt(10) < new int64.fromInt(11), true);
- expect(new int64.fromInt(10) < new int64.fromInt(10), false);
- expect(new int64.fromInt(10) < new int64.fromInt(9), false);
- expect(new int64.fromInt(10) < new int32.fromInt(11), true);
- expect(new int64.fromInt(10) < new int32.fromInt(10), false);
- expect(new int64.fromInt(10) < new int32.fromInt(9), false);
- expect(new int64.fromInt(-10) < new int64.fromInt(-11), false);
- expect(int64.MIN_VALUE < new int64.fromInt(0), true);
+ expect(new Int64.fromInt(10) < new Int64.fromInt(11), true);
+ expect(new Int64.fromInt(10) < new Int64.fromInt(10), false);
+ expect(new Int64.fromInt(10) < new Int64.fromInt(9), false);
+ expect(new Int64.fromInt(10) < new Int32.fromInt(11), true);
+ expect(new Int64.fromInt(10) < new Int32.fromInt(10), false);
+ expect(new Int64.fromInt(10) < new Int32.fromInt(9), false);
+ expect(new Int64.fromInt(-10) < new Int64.fromInt(-11), false);
+ expect(Int64.MIN_VALUE < new Int64.fromInt(0), true);
expect(largeNeg < largePos, true);
expect(largePos < largePosPlusOne, true);
expect(largePos < largePos, false);
expect(largePosPlusOne < largePos, false);
- expect(int64.MIN_VALUE < int64.MAX_VALUE, true);
- expect(int64.MAX_VALUE < int64.MIN_VALUE, false);
- expect(() => new int64.fromInt(17) < null, throwsArgumentError);
+ expect(Int64.MIN_VALUE < Int64.MAX_VALUE, true);
+ expect(Int64.MAX_VALUE < Int64.MIN_VALUE, false);
+ expect(() => new Int64.fromInt(17) < null, throwsArgumentError);
});
test("<=", () {
- expect(new int64.fromInt(10) <= new int64.fromInt(11), true);
- expect(new int64.fromInt(10) <= new int64.fromInt(10), true);
- expect(new int64.fromInt(10) <= new int64.fromInt(9), false);
- expect(new int64.fromInt(10) <= new int32.fromInt(11), true);
- expect(new int64.fromInt(10) <= new int32.fromInt(10), true);
- expect(new int64.fromInt(10) <= new int64.fromInt(9), false);
- expect(new int64.fromInt(-10) <= new int64.fromInt(-11), false);
- expect(new int64.fromInt(-10) <= new int64.fromInt(-10), true);
+ expect(new Int64.fromInt(10) <= new Int64.fromInt(11), true);
+ expect(new Int64.fromInt(10) <= new Int64.fromInt(10), true);
+ expect(new Int64.fromInt(10) <= new Int64.fromInt(9), false);
+ expect(new Int64.fromInt(10) <= new Int32.fromInt(11), true);
+ expect(new Int64.fromInt(10) <= new Int32.fromInt(10), true);
+ expect(new Int64.fromInt(10) <= new Int64.fromInt(9), false);
+ expect(new Int64.fromInt(-10) <= new Int64.fromInt(-11), false);
+ expect(new Int64.fromInt(-10) <= new Int64.fromInt(-10), true);
expect(largeNeg <= largePos, true);
expect(largePos <= largeNeg, false);
expect(largePos <= largePosPlusOne, true);
expect(largePos <= largePos, true);
expect(largePosPlusOne <= largePos, false);
- expect(int64.MIN_VALUE <= int64.MAX_VALUE, true);
- expect(int64.MAX_VALUE <= int64.MIN_VALUE, false);
- expect(() => new int64.fromInt(17) <= null, throwsArgumentError);
+ expect(Int64.MIN_VALUE <= Int64.MAX_VALUE, true);
+ expect(Int64.MAX_VALUE <= Int64.MIN_VALUE, false);
+ expect(() => new Int64.fromInt(17) <= null, throwsArgumentError);
});
test("==", () {
- expect(new int64.fromInt(10) == new int64.fromInt(11), false);
- expect(new int64.fromInt(10) == new int64.fromInt(10), true);
- expect(new int64.fromInt(10) == new int64.fromInt(9), false);
- expect(new int64.fromInt(10) == new int32.fromInt(11), false);
- expect(new int64.fromInt(10) == new int32.fromInt(10), true);
- expect(new int64.fromInt(10) == new int32.fromInt(9), false);
- expect(new int64.fromInt(-10) == new int64.fromInt(-10), true);
- expect(new int64.fromInt(-10) != new int64.fromInt(-10), false);
+ expect(new Int64.fromInt(10) == new Int64.fromInt(11), false);
+ expect(new Int64.fromInt(10) == new Int64.fromInt(10), true);
+ expect(new Int64.fromInt(10) == new Int64.fromInt(9), false);
+ expect(new Int64.fromInt(10) == new Int32.fromInt(11), false);
+ expect(new Int64.fromInt(10) == new Int32.fromInt(10), true);
+ expect(new Int64.fromInt(10) == new Int32.fromInt(9), false);
+ expect(new Int64.fromInt(-10) == new Int64.fromInt(-10), true);
+ expect(new Int64.fromInt(-10) != new Int64.fromInt(-10), false);
expect(largePos == largePos, true);
expect(largePos == largePosPlusOne, false);
expect(largePosPlusOne == largePos, false);
- expect(int64.MIN_VALUE == int64.MAX_VALUE, false);
- expect(new int64.fromInt(17) == new Object(), false);
- expect(new int64.fromInt(17) == null, false);
+ expect(Int64.MIN_VALUE == Int64.MAX_VALUE, false);
+ expect(new Int64.fromInt(17) == new Object(), false);
+ expect(new Int64.fromInt(17) == null, false);
});
test(">=", () {
- expect(new int64.fromInt(10) >= new int64.fromInt(11), false);
- expect(new int64.fromInt(10) >= new int64.fromInt(10), true);
- expect(new int64.fromInt(10) >= new int64.fromInt(9), true);
- expect(new int64.fromInt(10) >= new int32.fromInt(11), false);
- expect(new int64.fromInt(10) >= new int32.fromInt(10), true);
- expect(new int64.fromInt(10) >= new int32.fromInt(9), true);
- expect(new int64.fromInt(-10) >= new int64.fromInt(-11), true);
- expect(new int64.fromInt(-10) >= new int64.fromInt(-10), true);
+ expect(new Int64.fromInt(10) >= new Int64.fromInt(11), false);
+ expect(new Int64.fromInt(10) >= new Int64.fromInt(10), true);
+ expect(new Int64.fromInt(10) >= new Int64.fromInt(9), true);
+ expect(new Int64.fromInt(10) >= new Int32.fromInt(11), false);
+ expect(new Int64.fromInt(10) >= new Int32.fromInt(10), true);
+ expect(new Int64.fromInt(10) >= new Int32.fromInt(9), true);
+ expect(new Int64.fromInt(-10) >= new Int64.fromInt(-11), true);
+ expect(new Int64.fromInt(-10) >= new Int64.fromInt(-10), true);
expect(largePos >= largeNeg, true);
expect(largeNeg >= largePos, false);
expect(largePos >= largePosPlusOne, false);
expect(largePos >= largePos, true);
expect(largePosPlusOne >= largePos, true);
- expect(int64.MIN_VALUE >= int64.MAX_VALUE, false);
- expect(int64.MAX_VALUE >= int64.MIN_VALUE, true);
- expect(() => new int64.fromInt(17) >= null, throwsArgumentError);
+ expect(Int64.MIN_VALUE >= Int64.MAX_VALUE, false);
+ expect(Int64.MAX_VALUE >= Int64.MIN_VALUE, true);
+ expect(() => new Int64.fromInt(17) >= null, throwsArgumentError);
});
test(">", () {
- expect(new int64.fromInt(10) > new int64.fromInt(11), false);
- expect(new int64.fromInt(10) > new int64.fromInt(10), false);
- expect(new int64.fromInt(10) > new int64.fromInt(9), true);
- expect(new int64.fromInt(10) > new int32.fromInt(11), false);
- expect(new int64.fromInt(10) > new int32.fromInt(10), false);
- expect(new int64.fromInt(10) > new int32.fromInt(9), true);
- expect(new int64.fromInt(-10) > new int64.fromInt(-11), true);
- expect(new int64.fromInt(10) > new int64.fromInt(-11), true);
- expect(new int64.fromInt(-10) > new int64.fromInt(11), false);
+ expect(new Int64.fromInt(10) > new Int64.fromInt(11), false);
+ expect(new Int64.fromInt(10) > new Int64.fromInt(10), false);
+ expect(new Int64.fromInt(10) > new Int64.fromInt(9), true);
+ expect(new Int64.fromInt(10) > new Int32.fromInt(11), false);
+ expect(new Int64.fromInt(10) > new Int32.fromInt(10), false);
+ expect(new Int64.fromInt(10) > new Int32.fromInt(9), true);
+ expect(new Int64.fromInt(-10) > new Int64.fromInt(-11), true);
+ expect(new Int64.fromInt(10) > new Int64.fromInt(-11), true);
+ expect(new Int64.fromInt(-10) > new Int64.fromInt(11), false);
expect(largePos > largeNeg, true);
expect(largeNeg > largePos, false);
expect(largePos > largePosPlusOne, false);
expect(largePos > largePos, false);
expect(largePosPlusOne > largePos, true);
- expect(new int64.fromInt(0) > int64.MIN_VALUE, true);
- expect(int64.MIN_VALUE > int64.MAX_VALUE, false);
- expect(int64.MAX_VALUE > int64.MIN_VALUE, true);
- expect(() => new int64.fromInt(17) > null, throwsArgumentError);
+ expect(new Int64.fromInt(0) > Int64.MIN_VALUE, true);
+ expect(Int64.MIN_VALUE > Int64.MAX_VALUE, false);
+ expect(Int64.MAX_VALUE > Int64.MIN_VALUE, true);
+ expect(() => new Int64.fromInt(17) > null, throwsArgumentError);
});
});
group("bitwise operators", () {
- int64 n1 = new int64.fromInt(1234);
- int64 n2 = new int64.fromInt(9876);
- int64 n3 = new int64.fromInt(-1234);
- int64 n4 = new int64.fromInt(0x1234) << 32;
- int64 n5 = new int64.fromInt(0x9876) << 32;
+ Int64 n1 = new Int64.fromInt(1234);
+ Int64 n2 = new Int64.fromInt(9876);
+ Int64 n3 = new Int64.fromInt(-1234);
+ Int64 n4 = new Int64.fromInt(0x1234) << 32;
+ Int64 n5 = new Int64.fromInt(0x9876) << 32;
test("&", () {
- expect(n1 & n2, new int64.fromInt(1168));
- expect(n3 & n2, new int64.fromInt(8708));
- expect(n4 & n5, new int64.fromInt(0x1034) << 32);
+ expect(n1 & n2, new Int64.fromInt(1168));
+ expect(n3 & n2, new Int64.fromInt(8708));
+ expect(n4 & n5, new Int64.fromInt(0x1034) << 32);
expect(() => n1 & null, throwsArgumentError);
});
test("|", () {
- expect(n1 | n2, new int64.fromInt(9942));
- expect(n3 | n2, new int64.fromInt(-66));
- expect(n4 | n5, new int64.fromInt(0x9a76) << 32);
+ expect(n1 | n2, new Int64.fromInt(9942));
+ expect(n3 | n2, new Int64.fromInt(-66));
+ expect(n4 | n5, new Int64.fromInt(0x9a76) << 32);
expect(() => n1 | null, throwsArgumentError);
});
test("^", () {
- expect(n1 ^ n2, new int64.fromInt(8774));
- expect(n3 ^ n2, new int64.fromInt(-8774));
- expect(n4 ^ n5, new int64.fromInt(0x8a42) << 32);
+ expect(n1 ^ n2, new Int64.fromInt(8774));
+ expect(n3 ^ n2, new Int64.fromInt(-8774));
+ expect(n4 ^ n5, new Int64.fromInt(0x8a42) << 32);
expect(() => n1 ^ null, throwsArgumentError);
});
test("~", () {
- expect(-new int64.fromInt(1), new int64.fromInt(-1));
- expect(-new int64.fromInt(-1), new int64.fromInt(1));
- expect(-int64.MIN_VALUE, int64.MIN_VALUE);
+ expect(-new Int64.fromInt(1), new Int64.fromInt(-1));
+ expect(-new Int64.fromInt(-1), new Int64.fromInt(1));
+ expect(-Int64.MIN_VALUE, Int64.MIN_VALUE);
- expect(~n1, new int64.fromInt(-1235));
- expect(~n2, new int64.fromInt(-9877));
- expect(~n3, new int64.fromInt(1233));
- expect(~n4, new int64.fromInts(0xffffedcb, 0xffffffff));
- expect(~n5, new int64.fromInts(0xffff6789, 0xffffffff));
+ expect(~n1, new Int64.fromInt(-1235));
+ expect(~n2, new Int64.fromInt(-9877));
+ expect(~n3, new Int64.fromInt(1233));
+ expect(~n4, new Int64.fromInts(0xffffedcb, 0xffffffff));
+ expect(~n5, new Int64.fromInts(0xffff6789, 0xffffffff));
});
});
group("bitshift operators", () {
test("<<", () {
- expect(new int64.fromInts(0x12341234, 0x45674567) << 10,
- new int64.fromInts(0xd048d115, 0x9d159c00));
- expect(new int64.fromInts(0x92341234, 0x45674567) << 10,
- new int64.fromInts(0xd048d115, 0x9d159c00));
- expect(new int64.fromInt(-1) << 5, new int64.fromInt(-32));
- expect(new int64.fromInt(-1) << 0, new int64.fromInt(-1));
- expect(() => new int64.fromInt(17) << -1, throwsArgumentError);
- expect(() => new int64.fromInt(17) << null, throws);
+ expect(new Int64.fromInts(0x12341234, 0x45674567) << 10,
+ new Int64.fromInts(0xd048d115, 0x9d159c00));
+ expect(new Int64.fromInts(0x92341234, 0x45674567) << 10,
+ new Int64.fromInts(0xd048d115, 0x9d159c00));
+ expect(new Int64.fromInt(-1) << 5, new Int64.fromInt(-32));
+ expect(new Int64.fromInt(-1) << 0, new Int64.fromInt(-1));
+ expect(() => new Int64.fromInt(17) << -1, throwsArgumentError);
+ expect(() => new Int64.fromInt(17) << null, throws);
});
test(">>", () {
- expect((int64.MIN_VALUE >> 13).toString(), "-1125899906842624");
- expect(new int64.fromInts(0x12341234, 0x45674567) >> 10,
- new int64.fromInts(0x48d04, 0x8d1159d1));
- expect(new int64.fromInts(0x92341234, 0x45674567) >> 10,
- new int64.fromInts(0xffe48d04, 0x8d1159d1));
- expect(new int64.fromInts(0xFFFFFFF, 0xFFFFFFFF) >> 34,
- new int64.fromInt(67108863));
+ expect((Int64.MIN_VALUE >> 13).toString(), "-1125899906842624");
+ expect(new Int64.fromInts(0x12341234, 0x45674567) >> 10,
+ new Int64.fromInts(0x48d04, 0x8d1159d1));
+ expect(new Int64.fromInts(0x92341234, 0x45674567) >> 10,
+ new Int64.fromInts(0xffe48d04, 0x8d1159d1));
+ expect(new Int64.fromInts(0xFFFFFFF, 0xFFFFFFFF) >> 34,
+ new Int64.fromInt(67108863));
for (int n = 0; n <= 66; n++) {
- expect(new int64.fromInt(-1) >> n, new int64.fromInt(-1));
+ expect(new Int64.fromInt(-1) >> n, new Int64.fromInt(-1));
}
- expect(new int64.fromInts(0x72345678, 0x9abcdef0) >> 8,
- new int64.fromInts(0x00723456, 0x789abcde));
- expect(new int64.fromInts(0x72345678, 0x9abcdef0) >> 16,
- new int64.fromInts(0x00007234, 0x56789abc));
- expect(new int64.fromInts(0x72345678, 0x9abcdef0) >> 24,
- new int64.fromInts(0x00000072, 0x3456789a));
- expect(new int64.fromInts(0x72345678, 0x9abcdef0) >> 28,
- new int64.fromInts(0x00000007, 0x23456789));
- expect(new int64.fromInts(0x72345678, 0x9abcdef0) >> 32,
- new int64.fromInts(0x00000000, 0x72345678));
- expect(new int64.fromInts(0x72345678, 0x9abcdef0) >> 36,
- new int64.fromInts(0x00000000, 0x07234567));
- expect(new int64.fromInts(0x72345678, 0x9abcdef0) >> 40,
- new int64.fromInts(0x00000000, 0x00723456));
- expect(new int64.fromInts(0x72345678, 0x9abcde00) >> 44,
- new int64.fromInts(0x00000000, 0x00072345));
- expect(new int64.fromInts(0x72345678, 0x9abcdef0) >> 48,
- new int64.fromInts(0x00000000, 0x00007234));
- expect(new int64.fromInts(0x92345678, 0x9abcdef0) >> 8,
- new int64.fromInts(0xff923456, 0x789abcde));
- expect(new int64.fromInts(0x92345678, 0x9abcdef0) >> 16,
- new int64.fromInts(0xffff9234, 0x56789abc));
- expect(new int64.fromInts(0x92345678, 0x9abcdef0) >> 24,
- new int64.fromInts(0xffffff92, 0x3456789a));
- expect(new int64.fromInts(0x92345678, 0x9abcdef0) >> 28,
- new int64.fromInts(0xfffffff9, 0x23456789));
- expect(new int64.fromInts(0x92345678, 0x9abcdef0) >> 32,
- new int64.fromInts(0xffffffff, 0x92345678));
- expect(new int64.fromInts(0x92345678, 0x9abcdef0) >> 36,
- new int64.fromInts(0xffffffff, 0xf9234567));
- expect(new int64.fromInts(0x92345678, 0x9abcdef0) >> 40,
- new int64.fromInts(0xffffffff, 0xff923456));
- expect(new int64.fromInts(0x92345678, 0x9abcdef0) >> 44,
- new int64.fromInts(0xffffffff, 0xfff92345));
- expect(new int64.fromInts(0x92345678, 0x9abcdef0) >> 48,
- new int64.fromInts(0xffffffff, 0xffff9234));
- expect(() => new int64.fromInt(17) >> -1, throwsArgumentError);
- expect(() => new int64.fromInt(17) >> null, throws);
+ expect(new Int64.fromInts(0x72345678, 0x9abcdef0) >> 8,
+ new Int64.fromInts(0x00723456, 0x789abcde));
+ expect(new Int64.fromInts(0x72345678, 0x9abcdef0) >> 16,
+ new Int64.fromInts(0x00007234, 0x56789abc));
+ expect(new Int64.fromInts(0x72345678, 0x9abcdef0) >> 24,
+ new Int64.fromInts(0x00000072, 0x3456789a));
+ expect(new Int64.fromInts(0x72345678, 0x9abcdef0) >> 28,
+ new Int64.fromInts(0x00000007, 0x23456789));
+ expect(new Int64.fromInts(0x72345678, 0x9abcdef0) >> 32,
+ new Int64.fromInts(0x00000000, 0x72345678));
+ expect(new Int64.fromInts(0x72345678, 0x9abcdef0) >> 36,
+ new Int64.fromInts(0x00000000, 0x07234567));
+ expect(new Int64.fromInts(0x72345678, 0x9abcdef0) >> 40,
+ new Int64.fromInts(0x00000000, 0x00723456));
+ expect(new Int64.fromInts(0x72345678, 0x9abcde00) >> 44,
+ new Int64.fromInts(0x00000000, 0x00072345));
+ expect(new Int64.fromInts(0x72345678, 0x9abcdef0) >> 48,
+ new Int64.fromInts(0x00000000, 0x00007234));
+ expect(new Int64.fromInts(0x92345678, 0x9abcdef0) >> 8,
+ new Int64.fromInts(0xff923456, 0x789abcde));
+ expect(new Int64.fromInts(0x92345678, 0x9abcdef0) >> 16,
+ new Int64.fromInts(0xffff9234, 0x56789abc));
+ expect(new Int64.fromInts(0x92345678, 0x9abcdef0) >> 24,
+ new Int64.fromInts(0xffffff92, 0x3456789a));
+ expect(new Int64.fromInts(0x92345678, 0x9abcdef0) >> 28,
+ new Int64.fromInts(0xfffffff9, 0x23456789));
+ expect(new Int64.fromInts(0x92345678, 0x9abcdef0) >> 32,
+ new Int64.fromInts(0xffffffff, 0x92345678));
+ expect(new Int64.fromInts(0x92345678, 0x9abcdef0) >> 36,
+ new Int64.fromInts(0xffffffff, 0xf9234567));
+ expect(new Int64.fromInts(0x92345678, 0x9abcdef0) >> 40,
+ new Int64.fromInts(0xffffffff, 0xff923456));
+ expect(new Int64.fromInts(0x92345678, 0x9abcdef0) >> 44,
+ new Int64.fromInts(0xffffffff, 0xfff92345));
+ expect(new Int64.fromInts(0x92345678, 0x9abcdef0) >> 48,
+ new Int64.fromInts(0xffffffff, 0xffff9234));
+ expect(() => new Int64.fromInt(17) >> -1, throwsArgumentError);
+ expect(() => new Int64.fromInt(17) >> null, throws);
});
test("shiftRightUnsigned", () {
- expect(new int64.fromInts(0x12341234, 0x45674567).shiftRightUnsigned(10),
- new int64.fromInts(0x48d04, 0x8d1159d1));
- expect(new int64.fromInts(0x92341234, 0x45674567).shiftRightUnsigned(10),
- new int64.fromInts(0x248d04, 0x8d1159d1));
- expect(new int64.fromInts(0x72345678, 0x9abcdef0).shiftRightUnsigned(8),
- new int64.fromInts(0x00723456, 0x789abcde));
- expect(new int64.fromInts(0x72345678, 0x9abcdef0).shiftRightUnsigned(16),
- new int64.fromInts(0x00007234, 0x56789abc));
- expect(new int64.fromInts(0x72345678, 0x9abcdef0).shiftRightUnsigned(24),
- new int64.fromInts(0x00000072, 0x3456789a));
- expect(new int64.fromInts(0x72345678, 0x9abcdef0).shiftRightUnsigned(28),
- new int64.fromInts(0x00000007, 0x23456789));
- expect(new int64.fromInts(0x72345678, 0x9abcdef0).shiftRightUnsigned(32),
- new int64.fromInts(0x00000000, 0x72345678));
- expect(new int64.fromInts(0x72345678, 0x9abcdef0).shiftRightUnsigned(36),
- new int64.fromInts(0x00000000, 0x07234567));
- expect(new int64.fromInts(0x72345678, 0x9abcdef0).shiftRightUnsigned(40),
- new int64.fromInts(0x00000000, 0x00723456));
- expect(new int64.fromInts(0x72345678, 0x9abcde00).shiftRightUnsigned(44),
- new int64.fromInts(0x00000000, 0x00072345));
- expect(new int64.fromInts(0x72345678, 0x9abcdef0).shiftRightUnsigned(48),
- new int64.fromInts(0x00000000, 0x00007234));
- expect(new int64.fromInts(0x92345678, 0x9abcdef0).shiftRightUnsigned(8),
- new int64.fromInts(0x00923456, 0x789abcde));
- expect(new int64.fromInts(0x92345678, 0x9abcdef0).shiftRightUnsigned(16),
- new int64.fromInts(0x00009234, 0x56789abc));
- expect(new int64.fromInts(0x92345678, 0x9abcdef0).shiftRightUnsigned(24),
- new int64.fromInts(0x00000092, 0x3456789a));
- expect(new int64.fromInts(0x92345678, 0x9abcdef0).shiftRightUnsigned(28),
- new int64.fromInts(0x00000009, 0x23456789));
- expect(new int64.fromInts(0x92345678, 0x9abcdef0).shiftRightUnsigned(32),
- new int64.fromInts(0x00000000, 0x92345678));
- expect(new int64.fromInts(0x92345678, 0x9abcdef0).shiftRightUnsigned(36),
- new int64.fromInts(0x00000000, 0x09234567));
- expect(new int64.fromInts(0x92345678, 0x9abcdef0).shiftRightUnsigned(40),
- new int64.fromInts(0x00000000, 0x00923456));
- expect(new int64.fromInts(0x92345678, 0x9abcdef0).shiftRightUnsigned(44),
- new int64.fromInts(0x00000000, 0x00092345));
- expect(new int64.fromInts(0x00000000, 0x00009234),
- new int64.fromInts(0x92345678, 0x9abcdef0).shiftRightUnsigned(48));
- expect(() => new int64.fromInt(17).shiftRightUnsigned(-1),
+ expect(new Int64.fromInts(0x12341234, 0x45674567).shiftRightUnsigned(10),
+ new Int64.fromInts(0x48d04, 0x8d1159d1));
+ expect(new Int64.fromInts(0x92341234, 0x45674567).shiftRightUnsigned(10),
+ new Int64.fromInts(0x248d04, 0x8d1159d1));
+ expect(new Int64.fromInts(0x72345678, 0x9abcdef0).shiftRightUnsigned(8),
+ new Int64.fromInts(0x00723456, 0x789abcde));
+ expect(new Int64.fromInts(0x72345678, 0x9abcdef0).shiftRightUnsigned(16),
+ new Int64.fromInts(0x00007234, 0x56789abc));
+ expect(new Int64.fromInts(0x72345678, 0x9abcdef0).shiftRightUnsigned(24),
+ new Int64.fromInts(0x00000072, 0x3456789a));
+ expect(new Int64.fromInts(0x72345678, 0x9abcdef0).shiftRightUnsigned(28),
+ new Int64.fromInts(0x00000007, 0x23456789));
+ expect(new Int64.fromInts(0x72345678, 0x9abcdef0).shiftRightUnsigned(32),
+ new Int64.fromInts(0x00000000, 0x72345678));
+ expect(new Int64.fromInts(0x72345678, 0x9abcdef0).shiftRightUnsigned(36),
+ new Int64.fromInts(0x00000000, 0x07234567));
+ expect(new Int64.fromInts(0x72345678, 0x9abcdef0).shiftRightUnsigned(40),
+ new Int64.fromInts(0x00000000, 0x00723456));
+ expect(new Int64.fromInts(0x72345678, 0x9abcde00).shiftRightUnsigned(44),
+ new Int64.fromInts(0x00000000, 0x00072345));
+ expect(new Int64.fromInts(0x72345678, 0x9abcdef0).shiftRightUnsigned(48),
+ new Int64.fromInts(0x00000000, 0x00007234));
+ expect(new Int64.fromInts(0x92345678, 0x9abcdef0).shiftRightUnsigned(8),
+ new Int64.fromInts(0x00923456, 0x789abcde));
+ expect(new Int64.fromInts(0x92345678, 0x9abcdef0).shiftRightUnsigned(16),
+ new Int64.fromInts(0x00009234, 0x56789abc));
+ expect(new Int64.fromInts(0x92345678, 0x9abcdef0).shiftRightUnsigned(24),
+ new Int64.fromInts(0x00000092, 0x3456789a));
+ expect(new Int64.fromInts(0x92345678, 0x9abcdef0).shiftRightUnsigned(28),
+ new Int64.fromInts(0x00000009, 0x23456789));
+ expect(new Int64.fromInts(0x92345678, 0x9abcdef0).shiftRightUnsigned(32),
+ new Int64.fromInts(0x00000000, 0x92345678));
+ expect(new Int64.fromInts(0x92345678, 0x9abcdef0).shiftRightUnsigned(36),
+ new Int64.fromInts(0x00000000, 0x09234567));
+ expect(new Int64.fromInts(0x92345678, 0x9abcdef0).shiftRightUnsigned(40),
+ new Int64.fromInts(0x00000000, 0x00923456));
+ expect(new Int64.fromInts(0x92345678, 0x9abcdef0).shiftRightUnsigned(44),
+ new Int64.fromInts(0x00000000, 0x00092345));
+ expect(new Int64.fromInts(0x00000000, 0x00009234),
+ new Int64.fromInts(0x92345678, 0x9abcdef0).shiftRightUnsigned(48));
+ expect(() => new Int64.fromInt(17).shiftRightUnsigned(-1),
throwsArgumentError);
- expect(() => new int64.fromInt(17).shiftRightUnsigned(null), throws);
+ expect(() => new Int64.fromInt(17).shiftRightUnsigned(null), throws);
});
test("overflow", () {
- expect((new int64.fromInt(1) << 63) >> 1,
- -new int64.fromInts(0x40000000, 0x00000000));
- expect((new int64.fromInt(-1) << 32) << 32, new int64.fromInt(0));
- expect(int64.MIN_VALUE << 0, int64.MIN_VALUE);
- expect(int64.MIN_VALUE << 1, new int64.fromInt(0));
- expect((-new int64.fromInts(8, 0)) >> 1,
- new int64.fromInts(0xfffffffc, 0x00000000));
- expect((-new int64.fromInts(8, 0)).shiftRightUnsigned(1),
- new int64.fromInts(0x7ffffffc, 0x0));
+ expect((new Int64.fromInt(1) << 63) >> 1,
+ -new Int64.fromInts(0x40000000, 0x00000000));
+ expect((new Int64.fromInt(-1) << 32) << 32, new Int64.fromInt(0));
+ expect(Int64.MIN_VALUE << 0, Int64.MIN_VALUE);
+ expect(Int64.MIN_VALUE << 1, new Int64.fromInt(0));
+ expect((-new Int64.fromInts(8, 0)) >> 1,
+ new Int64.fromInts(0xfffffffc, 0x00000000));
+ expect((-new Int64.fromInts(8, 0)).shiftRightUnsigned(1),
+ new Int64.fromInts(0x7ffffffc, 0x0));
});
});
group("type conversions", () {
test("toInt", () {
- expect(new int64.fromInt(0).toInt(), 0);
- expect(new int64.fromInt(100).toInt(), 100);
- expect(new int64.fromInt(-100).toInt(), -100);
- expect(new int64.fromInt(2147483647).toInt(), 2147483647);
- expect(new int64.fromInt(2147483648).toInt(), 2147483648);
- expect(new int64.fromInt(-2147483647).toInt(), -2147483647);
- expect(new int64.fromInt(-2147483648).toInt(), -2147483648);
- expect(new int64.fromInt(4503599627370495).toInt(), 4503599627370495);
- expect(new int64.fromInt(4503599627370496).toInt(), 4503599627370496);
- expect(new int64.fromInt(-4503599627370495).toInt(), -4503599627370495);
- expect(new int64.fromInt(-4503599627370496).toInt(), -4503599627370496);
+ expect(new Int64.fromInt(0).toInt(), 0);
+ expect(new Int64.fromInt(100).toInt(), 100);
+ expect(new Int64.fromInt(-100).toInt(), -100);
+ expect(new Int64.fromInt(2147483647).toInt(), 2147483647);
+ expect(new Int64.fromInt(2147483648).toInt(), 2147483648);
+ expect(new Int64.fromInt(-2147483647).toInt(), -2147483647);
+ expect(new Int64.fromInt(-2147483648).toInt(), -2147483648);
+ expect(new Int64.fromInt(4503599627370495).toInt(), 4503599627370495);
+ expect(new Int64.fromInt(4503599627370496).toInt(), 4503599627370496);
+ expect(new Int64.fromInt(-4503599627370495).toInt(), -4503599627370495);
+ expect(new Int64.fromInt(-4503599627370496).toInt(), -4503599627370496);
});
test("toInt32", () {
- expect(new int64.fromInt(0).toInt32(), new int32.fromInt(0));
- expect(new int64.fromInt(1).toInt32(), new int32.fromInt(1));
- expect(new int64.fromInt(-1).toInt32(), new int32.fromInt(-1));
- expect(new int64.fromInt(2147483647).toInt32(),
- new int32.fromInt(2147483647));
- expect(new int64.fromInt(2147483648).toInt32(),
- new int32.fromInt(-2147483648));
- expect(new int64.fromInt(2147483649).toInt32(),
- new int32.fromInt(-2147483647));
- expect(new int64.fromInt(2147483650).toInt32(),
- new int32.fromInt(-2147483646));
- expect(new int64.fromInt(-2147483648).toInt32(),
- new int32.fromInt(-2147483648));
- expect(new int64.fromInt(-2147483649).toInt32(),
- new int32.fromInt(2147483647));
- expect(new int64.fromInt(-2147483650).toInt32(),
- new int32.fromInt(2147483646));
- expect(new int64.fromInt(-2147483651).toInt32(),
- new int32.fromInt(2147483645));
+ expect(new Int64.fromInt(0).toInt32(), new Int32.fromInt(0));
+ expect(new Int64.fromInt(1).toInt32(), new Int32.fromInt(1));
+ expect(new Int64.fromInt(-1).toInt32(), new Int32.fromInt(-1));
+ expect(new Int64.fromInt(2147483647).toInt32(),
+ new Int32.fromInt(2147483647));
+ expect(new Int64.fromInt(2147483648).toInt32(),
+ new Int32.fromInt(-2147483648));
+ expect(new Int64.fromInt(2147483649).toInt32(),
+ new Int32.fromInt(-2147483647));
+ expect(new Int64.fromInt(2147483650).toInt32(),
+ new Int32.fromInt(-2147483646));
+ expect(new Int64.fromInt(-2147483648).toInt32(),
+ new Int32.fromInt(-2147483648));
+ expect(new Int64.fromInt(-2147483649).toInt32(),
+ new Int32.fromInt(2147483647));
+ expect(new Int64.fromInt(-2147483650).toInt32(),
+ new Int32.fromInt(2147483646));
+ expect(new Int64.fromInt(-2147483651).toInt32(),
+ new Int32.fromInt(2147483645));
});
});
test("JavaScript 53-bit integer boundary", () {
- int64 _factorial(int64 n) {
+ Int64 _factorial(Int64 n) {
if (n.isZero) {
- return new int64.fromInt(1);
+ return new Int64.fromInt(1);
} else {
- return n * _factorial(n - new int64.fromInt(1));
+ return n * _factorial(n - new Int64.fromInt(1));
}
}
- int64 fact18 = _factorial(new int64.fromInt(18));
- int64 fact17 = _factorial(new int64.fromInt(17));
- expect(fact18 ~/ fact17, new int64.fromInt(18));
+ Int64 fact18 = _factorial(new Int64.fromInt(18));
+ Int64 fact17 = _factorial(new Int64.fromInt(17));
+ expect(fact18 ~/ fact17, new Int64.fromInt(18));
});
test("min, max values", () {
- expect(new int64.fromInt(1) << 63, int64.MIN_VALUE);
- expect(-(int64.MIN_VALUE + new int64.fromInt(1)), int64.MAX_VALUE);
+ expect(new Int64.fromInt(1) << 63, Int64.MIN_VALUE);
+ expect(-(Int64.MIN_VALUE + new Int64.fromInt(1)), Int64.MAX_VALUE);
});
group("string representation", () {
test("toString", () {
- expect(new int64.fromInt(0).toString(), "0");
- expect(new int64.fromInt(1).toString(), "1");
- expect(new int64.fromInt(-1).toString(), "-1");
- expect(new int64.fromInt(-10).toString(), "-10");
- expect(int64.MIN_VALUE.toString(), "-9223372036854775808");
- expect(int64.MAX_VALUE.toString(), "9223372036854775807");
+ expect(new Int64.fromInt(0).toString(), "0");
+ expect(new Int64.fromInt(1).toString(), "1");
+ expect(new Int64.fromInt(-1).toString(), "-1");
+ expect(new Int64.fromInt(-10).toString(), "-10");
+ expect(Int64.MIN_VALUE.toString(), "-9223372036854775808");
+ expect(Int64.MAX_VALUE.toString(), "9223372036854775807");
int top = 922337201;
int bottom = 967490662;
- int64 fullnum = (new int64.fromInt(1000000000) * new int64.fromInt(top)) +
- new int64.fromInt(bottom);
+ Int64 fullnum = (new Int64.fromInt(1000000000) * new Int64.fromInt(top)) +
+ new Int64.fromInt(bottom);
expect(fullnum.toString(), "922337201967490662");
expect((-fullnum).toString(), "-922337201967490662");
- expect(new int64.fromInt(123456789).toString(), "123456789");
+ expect(new Int64.fromInt(123456789).toString(), "123456789");
});
test("toHexString", () {
- int64 deadbeef12341234 = new int64.fromInts(0xDEADBEEF, 0x12341234);
- expect(int64.ZERO.toHexString(), "0");
+ Int64 deadbeef12341234 = new Int64.fromInts(0xDEADBEEF, 0x12341234);
+ expect(Int64.ZERO.toHexString(), "0");
expect(deadbeef12341234.toHexString(), "DEADBEEF12341234");
- expect(new int64.fromInts(0x17678A7, 0xDEF01234).toHexString(),
+ expect(new Int64.fromInts(0x17678A7, 0xDEF01234).toHexString(),
"17678A7DEF01234");
- expect(new int64.fromInt(123456789).toHexString(), "75BCD15");
+ expect(new Int64.fromInt(123456789).toHexString(), "75BCD15");
});
test("toRadixString", () {
- expect(new int64.fromInt(123456789).toRadixString(5), "223101104124");
- expect(int64.MIN_VALUE.toRadixString(2),
+ expect(new Int64.fromInt(123456789).toRadixString(5), "223101104124");
+ expect(Int64.MIN_VALUE.toRadixString(2),
"-1000000000000000000000000000000000000000000000000000000000000000");
- expect(int64.MIN_VALUE.toRadixString(3),
+ expect(Int64.MIN_VALUE.toRadixString(3),
"-2021110011022210012102010021220101220222");
- expect(int64.MIN_VALUE.toRadixString(4),
+ expect(Int64.MIN_VALUE.toRadixString(4),
"-20000000000000000000000000000000");
- expect(int64.MIN_VALUE.toRadixString(5), "-1104332401304422434310311213");
- expect(int64.MIN_VALUE.toRadixString(6), "-1540241003031030222122212");
- expect(int64.MIN_VALUE.toRadixString(7), "-22341010611245052052301");
- expect(int64.MIN_VALUE.toRadixString(8), "-1000000000000000000000");
- expect(int64.MIN_VALUE.toRadixString(9), "-67404283172107811828");
- expect(int64.MIN_VALUE.toRadixString(10), "-9223372036854775808");
- expect(int64.MIN_VALUE.toRadixString(11), "-1728002635214590698");
- expect(int64.MIN_VALUE.toRadixString(12), "-41A792678515120368");
- expect(int64.MIN_VALUE.toRadixString(13), "-10B269549075433C38");
- expect(int64.MIN_VALUE.toRadixString(14), "-4340724C6C71DC7A8");
- expect(int64.MIN_VALUE.toRadixString(15), "-160E2AD3246366808");
- expect(int64.MIN_VALUE.toRadixString(16), "-8000000000000000");
- expect(int64.MAX_VALUE.toRadixString(2),
+ expect(Int64.MIN_VALUE.toRadixString(5), "-1104332401304422434310311213");
+ expect(Int64.MIN_VALUE.toRadixString(6), "-1540241003031030222122212");
+ expect(Int64.MIN_VALUE.toRadixString(7), "-22341010611245052052301");
+ expect(Int64.MIN_VALUE.toRadixString(8), "-1000000000000000000000");
+ expect(Int64.MIN_VALUE.toRadixString(9), "-67404283172107811828");
+ expect(Int64.MIN_VALUE.toRadixString(10), "-9223372036854775808");
+ expect(Int64.MIN_VALUE.toRadixString(11), "-1728002635214590698");
+ expect(Int64.MIN_VALUE.toRadixString(12), "-41A792678515120368");
+ expect(Int64.MIN_VALUE.toRadixString(13), "-10B269549075433C38");
+ expect(Int64.MIN_VALUE.toRadixString(14), "-4340724C6C71DC7A8");
+ expect(Int64.MIN_VALUE.toRadixString(15), "-160E2AD3246366808");
+ expect(Int64.MIN_VALUE.toRadixString(16), "-8000000000000000");
+ expect(Int64.MAX_VALUE.toRadixString(2),
"111111111111111111111111111111111111111111111111111111111111111");
- expect(int64.MAX_VALUE.toRadixString(3),
+ expect(Int64.MAX_VALUE.toRadixString(3),
"2021110011022210012102010021220101220221");
- expect(int64.MAX_VALUE.toRadixString(4),
+ expect(Int64.MAX_VALUE.toRadixString(4),
"13333333333333333333333333333333");
- expect(int64.MAX_VALUE.toRadixString(5), "1104332401304422434310311212");
- expect(int64.MAX_VALUE.toRadixString(6), "1540241003031030222122211");
- expect(int64.MAX_VALUE.toRadixString(7), "22341010611245052052300");
- expect(int64.MAX_VALUE.toRadixString(8), "777777777777777777777");
- expect(int64.MAX_VALUE.toRadixString(9), "67404283172107811827");
- expect(int64.MAX_VALUE.toRadixString(10), "9223372036854775807");
- expect(int64.MAX_VALUE.toRadixString(11), "1728002635214590697");
- expect(int64.MAX_VALUE.toRadixString(12), "41A792678515120367");
- expect(int64.MAX_VALUE.toRadixString(13), "10B269549075433C37");
- expect(int64.MAX_VALUE.toRadixString(14), "4340724C6C71DC7A7");
- expect(int64.MAX_VALUE.toRadixString(15), "160E2AD3246366807");
- expect(int64.MAX_VALUE.toRadixString(16), "7FFFFFFFFFFFFFFF");
+ expect(Int64.MAX_VALUE.toRadixString(5), "1104332401304422434310311212");
+ expect(Int64.MAX_VALUE.toRadixString(6), "1540241003031030222122211");
+ expect(Int64.MAX_VALUE.toRadixString(7), "22341010611245052052300");
+ expect(Int64.MAX_VALUE.toRadixString(8), "777777777777777777777");
+ expect(Int64.MAX_VALUE.toRadixString(9), "67404283172107811827");
+ expect(Int64.MAX_VALUE.toRadixString(10), "9223372036854775807");
+ expect(Int64.MAX_VALUE.toRadixString(11), "1728002635214590697");
+ expect(Int64.MAX_VALUE.toRadixString(12), "41A792678515120367");
+ expect(Int64.MAX_VALUE.toRadixString(13), "10B269549075433C37");
+ expect(Int64.MAX_VALUE.toRadixString(14), "4340724C6C71DC7A7");
+ expect(Int64.MAX_VALUE.toRadixString(15), "160E2AD3246366807");
+ expect(Int64.MAX_VALUE.toRadixString(16), "7FFFFFFFFFFFFFFF");
});
});
}
diff --git a/pkg/mdv/lib/mdv.dart b/pkg/mdv/lib/mdv.dart
index 8c46580..8ba6bf6 100644
--- a/pkg/mdv/lib/mdv.dart
+++ b/pkg/mdv/lib/mdv.dart
@@ -47,29 +47,15 @@
*/
// TODO(rafaelw): This is a hack, and is neccesary for the polyfill
// because custom elements are not upgraded during clone()
+// TODO(jmesserly): polymer removed this in:
+// https://github.com/Polymer/platform/commit/344ffeaae475babb529403f6608588a0fc73f4e7
Stream<DocumentFragment> get instanceCreated {
if (_instanceCreated == null) {
- _instanceCreated =
- new StreamController<DocumentFragment>(sync: true);
+ _instanceCreated = new StreamController<DocumentFragment>(sync: true);
}
return _instanceCreated.stream;
}
-/**
- * Binds all mustaches recursively starting from the [root] node.
- *
- * Note: this is not an official Model-Driven-Views API; it is intended to
- * support binding the [ShadowRoot]'s content to a model.
- */
-// TODO(jmesserly): this is needed to avoid two <template> nodes when using
-// bindings in a custom element's template. See also:
-// https://github.com/polymer-project/polymer/blob/master/src/bindMDV.js#L68
-// Called from:
-// https://github.com/polymer-project/polymer/blob/master/src/register.js#L99
-void bindModel(Node root, model, [BindingDelegate delegate]) {
- _addBindings(root, model, delegate);
-}
-
// TODO(jmesserly): investigate if expandos give us enough performance.
diff --git a/pkg/mdv/lib/src/template_iterator.dart b/pkg/mdv/lib/src/template_iterator.dart
index 8cca7ce..6c87a42 100644
--- a/pkg/mdv/lib/src/template_iterator.dart
+++ b/pkg/mdv/lib/src/template_iterator.dart
@@ -99,14 +99,12 @@
return;
}
- var replacementBinding = new CompoundBinding();
- for (var i = 1; i < tokens.length; i += 2) {
- // TODO(jmesserly): not sure if this index is correct. See my comment here:
- // https://github.com/Polymer/mdv/commit/f1af6fe683fd06eed2a7a7849f01c227db12cda3#L0L1035
- _bindOrDelegate(replacementBinding, i, model, tokens[i], delegate);
- }
-
- replacementBinding.combinator = (values) {
+ // TODO(jmesserly): MDV caches the closure on the tokens, but I'm not sure
+ // why they do that instead of just caching the entire CompoundBinding object
+ // and unbindAll then bind to the new model.
+ var replacementBinding = new CompoundBinding()
+ ..scheduled = true
+ ..combinator = (values) {
var newValue = new StringBuffer();
for (var i = 0, text = true; i < tokens.length; i++, text = !text) {
@@ -123,6 +121,14 @@
return newValue.toString();
};
+ for (var i = 1; i < tokens.length; i += 2) {
+ // TODO(jmesserly): not sure if this index is correct. See my comment here:
+ // https://github.com/Polymer/mdv/commit/f1af6fe683fd06eed2a7a7849f01c227db12cda3#L0L1035
+ _bindOrDelegate(replacementBinding, i, model, tokens[i], delegate);
+ }
+
+ replacementBinding.resolve();
+
node.bind(name, replacementBinding, 'value');
}
@@ -159,7 +165,7 @@
* [TEXT, (PATH, TEXT)+] if there is at least one mustache.
*/
List<String> _parseMustacheTokens(String s) {
- if (s.isEmpty) return;
+ if (s.isEmpty) return null;
var tokens = null;
var length = s.length;
diff --git a/pkg/mdv/test/analyzer_test.dart b/pkg/mdv/test/analyzer_test.dart
new file mode 100644
index 0000000..68f5e85
--- /dev/null
+++ b/pkg/mdv/test/analyzer_test.dart
@@ -0,0 +1,12 @@
+// Copyright (c) 2013, 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 mdv.test.analyzer_test;
+
+import 'package:mdv/mdv.dart';
+
+// @static-clean
+
+// This test ensures MDV compiles without errors.
+void main() {}
diff --git a/pkg/mdv/test/template_element_test.dart b/pkg/mdv/test/template_element_test.dart
index d4cd501..a424e9e 100644
--- a/pkg/mdv/test/template_element_test.dart
+++ b/pkg/mdv/test/template_element_test.dart
@@ -1566,22 +1566,20 @@
}
});
- observeTest('BindShadowDOM bindModel', () {
+ observeTest('BindShadowDOM createInstance', () {
if (ShadowRoot.supported) {
- var root = createShadowTestHtml('Hi {{ name }}');
var model = toSymbolMap({'name': 'Leela'});
- mdv.bindModel(root, model);
+ var template = new Element.html('<template>Hi {{ name }}</template>');
+ var root = createShadowTestHtml('');
+ root.nodes.add(template.createInstance(model));
+
performMicrotaskCheckpoint();
expect(root.text, 'Hi Leela');
- }
- });
- observeTest('bindModel to polyfilled shadow root', () {
- var root = createTestHtml('Hi {{ name }}');
- var model = toSymbolMap({'name': 'Leela'});
- mdv.bindModel(root, model);
- performMicrotaskCheckpoint();
- expect(root.text, 'Hi Leela');
+ model[sym('name')] = 'Fry';
+ performMicrotaskCheckpoint();
+ expect(root.text, 'Hi Fry');
+ }
});
observeTest('BindShadowDOM Template Ref', () {
diff --git a/pkg/mutation_observer/README.md b/pkg/mutation_observer/README.md
new file mode 100644
index 0000000..ea4f66a
--- /dev/null
+++ b/pkg/mutation_observer/README.md
@@ -0,0 +1,42 @@
+# Mutation Observers polyfill
+
+Mutation Observers provide a way to react to changes in the DOM. This is needed
+on IE versions 9 and 10, see <http://caniuse.com/mutationobserver>.
+
+## More information
+
+* [API documentation](http://api.dartlang.org/docs/bleeding_edge/dart_html/MutationObserver.html)
+* [Mozilla Developer Network page](https://developer.mozilla.org/en-US/docs/Web/API/MutationObserver)
+* [Specification](https://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#mutation-observers)
+
+## Getting started
+
+Include the polyfill in your HTML `<head>`:
+
+```html
+ <script src="packages/mutation_observer/mutation_observer.js"></script>
+```
+
+You can also use a minified version for deployment:
+
+```html
+ <script src="packages/mutation_observer/mutation_observer.min.js"></script>
+```
+
+## Getting the source code
+
+The source for this package is at:
+<https://code.google.com/p/dart/source/browse/branches/bleeding_edge/dart/pkg/mutation_observer/>
+
+The original source of the JavaScript code is at:
+<https://github.com/Polymer/MutationObservers/tree/master>
+
+## Building
+
+The minified version is produced with:
+
+```bash
+ uglifyjs mutation_observer.js -o mutation_observer.min.js
+```
+
+See <https://github.com/mishoo/UglifyJS2> for usage of UglifyJS.
diff --git a/pkg/mutation_observer/lib/mutation_observer.js b/pkg/mutation_observer/lib/mutation_observer.js
new file mode 100644
index 0000000..cae8709
--- /dev/null
+++ b/pkg/mutation_observer/lib/mutation_observer.js
@@ -0,0 +1,588 @@
+/*
+ * Copyright 2013 The Polymer Authors. All rights reserved.
+ * Use of this source code is goverened by a BSD-style
+ * license that can be found in the LICENSE file.
+ */
+
+// TODO(jmesserly): polyfill does not have feature testing or the definition of
+// SideTable. The extra code is from:
+// https://github.com/Polymer/CustomElements/blob/master/src/MutationObserver.js
+// https://github.com/Polymer/CustomElements/blob/master/src/sidetable.js
+// I also renamed JsMutationObserver -> MutationObserver to correctly interact
+// with dart2js interceptors.
+
+if (!window.MutationObserver && !window.WebKitMutationObserver) {
+
+(function(global) {
+ // SideTable is a weak map where possible. If WeakMap is not available the
+ // association is stored as an expando property.
+ var SideTable;
+ // TODO(arv): WeakMap does not allow for Node etc to be keys in Firefox
+ if (typeof WeakMap !== 'undefined' && navigator.userAgent.indexOf('Firefox/') < 0) {
+ SideTable = WeakMap;
+ } else {
+ (function() {
+ var defineProperty = Object.defineProperty;
+ var hasOwnProperty = Object.hasOwnProperty;
+ var counter = new Date().getTime() % 1e9;
+
+ SideTable = function() {
+ this.name = '__st' + (Math.random() * 1e9 >>> 0) + (counter++ + '__');
+ };
+
+ SideTable.prototype = {
+ set: function(key, value) {
+ defineProperty(key, this.name, {value: value, writable: true});
+ },
+ get: function(key) {
+ return hasOwnProperty.call(key, this.name) ? key[this.name] : undefined;
+ },
+ delete: function(key) {
+ this.set(key, undefined);
+ }
+ }
+ })();
+ }
+
+ var registrationsTable = new SideTable();
+
+ // We use setImmediate or postMessage for our future callback.
+ var setImmediate = window.msSetImmediate;
+
+ // Use post message to emulate setImmediate.
+ if (!setImmediate) {
+ var setImmediateQueue = [];
+ var sentinel = String(Math.random());
+ window.addEventListener('message', function(e) {
+ if (e.data === sentinel) {
+ var queue = setImmediateQueue;
+ setImmediateQueue = [];
+ queue.forEach(function(func) {
+ func();
+ });
+ }
+ });
+ setImmediate = function(func) {
+ setImmediateQueue.push(func);
+ window.postMessage(sentinel, '*');
+ };
+ }
+
+ // This is used to ensure that we never schedule 2 callas to setImmediate
+ var isScheduled = false;
+
+ // Keep track of observers that needs to be notified next time.
+ var scheduledObservers = [];
+
+ /**
+ * Schedules |dispatchCallback| to be called in the future.
+ * @param {MutationObserver} observer
+ */
+ function scheduleCallback(observer) {
+ scheduledObservers.push(observer);
+ if (!isScheduled) {
+ isScheduled = true;
+ setImmediate(dispatchCallbacks);
+ }
+ }
+
+ function wrapIfNeeded(node) {
+ return window.ShadowDOMPolyfill &&
+ window.ShadowDOMPolyfill.wrapIfNeeded(node) ||
+ node;
+ }
+
+ function dispatchCallbacks() {
+ // http://dom.spec.whatwg.org/#mutation-observers
+
+ isScheduled = false; // Used to allow a new setImmediate call above.
+
+ var observers = scheduledObservers;
+ scheduledObservers = [];
+ // Sort observers based on their creation UID (incremental).
+ observers.sort(function(o1, o2) {
+ return o1.uid_ - o2.uid_;
+ });
+
+ var anyNonEmpty = false;
+ observers.forEach(function(observer) {
+
+ // 2.1, 2.2
+ var queue = observer.takeRecords();
+ // 2.3. Remove all transient registered observers whose observer is mo.
+ removeTransientObserversFor(observer);
+
+ // 2.4
+ if (queue.length) {
+ observer.callback_(queue, observer);
+ anyNonEmpty = true;
+ }
+ });
+
+ // 3.
+ if (anyNonEmpty)
+ dispatchCallbacks();
+ }
+
+ function removeTransientObserversFor(observer) {
+ observer.nodes_.forEach(function(node) {
+ var registrations = registrationsTable.get(node);
+ if (!registrations)
+ return;
+ registrations.forEach(function(registration) {
+ if (registration.observer === observer)
+ registration.removeTransientObservers();
+ });
+ });
+ }
+
+ /**
+ * This function is used for the "For each registered observer observer (with
+ * observer's options as options) in target's list of registered observers,
+ * run these substeps:" and the "For each ancestor ancestor of target, and for
+ * each registered observer observer (with options options) in ancestor's list
+ * of registered observers, run these substeps:" part of the algorithms. The
+ * |options.subtree| is checked to ensure that the callback is called
+ * correctly.
+ *
+ * @param {Node} target
+ * @param {function(MutationObserverInit):MutationRecord} callback
+ */
+ function forEachAncestorAndObserverEnqueueRecord(target, callback) {
+ for (var node = target; node; node = node.parentNode) {
+ var registrations = registrationsTable.get(node);
+
+ if (registrations) {
+ for (var j = 0; j < registrations.length; j++) {
+ var registration = registrations[j];
+ var options = registration.options;
+
+ // Only target ignores subtree.
+ if (node !== target && !options.subtree)
+ continue;
+
+ var record = callback(options);
+ if (record)
+ registration.enqueue(record);
+ }
+ }
+ }
+ }
+
+ var uidCounter = 0;
+
+ /**
+ * The class that maps to the DOM MutationObserver interface.
+ * @param {Function} callback.
+ * @constructor
+ */
+ function MutationObserver(callback) {
+ this.callback_ = callback;
+ this.nodes_ = [];
+ this.records_ = [];
+ this.uid_ = ++uidCounter;
+ }
+
+ MutationObserver.prototype = {
+ observe: function(target, options) {
+ target = wrapIfNeeded(target);
+
+ // 1.1
+ if (!options.childList && !options.attributes && !options.characterData ||
+
+ // 1.2
+ options.attributeOldValue && !options.attributes ||
+
+ // 1.3
+ options.attributeFilter && options.attributeFilter.length &&
+ !options.attributes ||
+
+ // 1.4
+ options.characterDataOldValue && !options.characterData) {
+
+ throw new SyntaxError();
+ }
+
+ var registrations = registrationsTable.get(target);
+ if (!registrations)
+ registrationsTable.set(target, registrations = []);
+
+ // 2
+ // If target's list of registered observers already includes a registered
+ // observer associated with the context object, replace that registered
+ // observer's options with options.
+ var registration;
+ for (var i = 0; i < registrations.length; i++) {
+ if (registrations[i].observer === this) {
+ registration = registrations[i];
+ registration.removeListeners();
+ registration.options = options;
+ break;
+ }
+ }
+
+ // 3.
+ // Otherwise, add a new registered observer to target's list of registered
+ // observers with the context object as the observer and options as the
+ // options, and add target to context object's list of nodes on which it
+ // is registered.
+ if (!registration) {
+ registration = new Registration(this, target, options);
+ registrations.push(registration);
+ this.nodes_.push(target);
+ }
+
+ registration.addListeners();
+ },
+
+ disconnect: function() {
+ this.nodes_.forEach(function(node) {
+ var registrations = registrationsTable.get(node);
+ for (var i = 0; i < registrations.length; i++) {
+ var registration = registrations[i];
+ if (registration.observer === this) {
+ registration.removeListeners();
+ registrations.splice(i, 1);
+ // Each node can only have one registered observer associated with
+ // this observer.
+ break;
+ }
+ }
+ }, this);
+ this.records_ = [];
+ },
+
+ takeRecords: function() {
+ var copyOfRecords = this.records_;
+ this.records_ = [];
+ return copyOfRecords;
+ }
+ };
+
+ /**
+ * @param {string} type
+ * @param {Node} target
+ * @constructor
+ */
+ function MutationRecord(type, target) {
+ this.type = type;
+ this.target = target;
+ this.addedNodes = [];
+ this.removedNodes = [];
+ this.previousSibling = null;
+ this.nextSibling = null;
+ this.attributeName = null;
+ this.attributeNamespace = null;
+ this.oldValue = null;
+ }
+
+ // TODO(jmesserly): this fixes the interceptor dispatch on IE.
+ // Not sure why this is necessary.
+ MutationObserver.prototype.constructor = MutationObserver;
+ MutationObserver.name = 'MutationObserver';
+ MutationRecord.prototype.constructor = MutationRecord;
+ MutationRecord.name = 'MutationRecord';
+
+ function copyMutationRecord(original) {
+ var record = new MutationRecord(original.type, original.target);
+ record.addedNodes = original.addedNodes.slice();
+ record.removedNodes = original.removedNodes.slice();
+ record.previousSibling = original.previousSibling;
+ record.nextSibling = original.nextSibling;
+ record.attributeName = original.attributeName;
+ record.attributeNamespace = original.attributeNamespace;
+ record.oldValue = original.oldValue;
+ return record;
+ };
+
+ // We keep track of the two (possibly one) records used in a single mutation.
+ var currentRecord, recordWithOldValue;
+
+ /**
+ * Creates a record without |oldValue| and caches it as |currentRecord| for
+ * later use.
+ * @param {string} oldValue
+ * @return {MutationRecord}
+ */
+ function getRecord(type, target) {
+ return currentRecord = new MutationRecord(type, target);
+ }
+
+ /**
+ * Gets or creates a record with |oldValue| based in the |currentRecord|
+ * @param {string} oldValue
+ * @return {MutationRecord}
+ */
+ function getRecordWithOldValue(oldValue) {
+ if (recordWithOldValue)
+ return recordWithOldValue;
+ recordWithOldValue = copyMutationRecord(currentRecord);
+ recordWithOldValue.oldValue = oldValue;
+ return recordWithOldValue;
+ }
+
+ function clearRecords() {
+ currentRecord = recordWithOldValue = undefined;
+ }
+
+ /**
+ * @param {MutationRecord} record
+ * @return {boolean} Whether the record represents a record from the current
+ * mutation event.
+ */
+ function recordRepresentsCurrentMutation(record) {
+ return record === recordWithOldValue || record === currentRecord;
+ }
+
+ /**
+ * Selects which record, if any, to replace the last record in the queue.
+ * This returns |null| if no record should be replaced.
+ *
+ * @param {MutationRecord} lastRecord
+ * @param {MutationRecord} newRecord
+ * @param {MutationRecord}
+ */
+ function selectRecord(lastRecord, newRecord) {
+ if (lastRecord === newRecord)
+ return lastRecord;
+
+ // Check if the the record we are adding represents the same record. If
+ // so, we keep the one with the oldValue in it.
+ if (recordWithOldValue && recordRepresentsCurrentMutation(lastRecord))
+ return recordWithOldValue;
+
+ return null;
+ }
+
+ /**
+ * Class used to represent a registered observer.
+ * @param {MutationObserver} observer
+ * @param {Node} target
+ * @param {MutationObserverInit} options
+ * @constructor
+ */
+ function Registration(observer, target, options) {
+ this.observer = observer;
+ this.target = target;
+ this.options = options;
+ this.transientObservedNodes = [];
+ }
+
+ Registration.prototype = {
+ enqueue: function(record) {
+ var records = this.observer.records_;
+ var length = records.length;
+
+ // There are cases where we replace the last record with the new record.
+ // For example if the record represents the same mutation we need to use
+ // the one with the oldValue. If we get same record (this can happen as we
+ // walk up the tree) we ignore the new record.
+ if (records.length > 0) {
+ var lastRecord = records[length - 1];
+ var recordToReplaceLast = selectRecord(lastRecord, record);
+ if (recordToReplaceLast) {
+ records[length - 1] = recordToReplaceLast;
+ return;
+ }
+ } else {
+ scheduleCallback(this.observer);
+ }
+
+ records[length] = record;
+ },
+
+ addListeners: function() {
+ this.addListeners_(this.target);
+ },
+
+ addListeners_: function(node) {
+ var options = this.options;
+ if (options.attributes)
+ node.addEventListener('DOMAttrModified', this, true);
+
+ if (options.characterData)
+ node.addEventListener('DOMCharacterDataModified', this, true);
+
+ if (options.childList)
+ node.addEventListener('DOMNodeInserted', this, true);
+
+ if (options.childList || options.subtree)
+ node.addEventListener('DOMNodeRemoved', this, true);
+ },
+
+ removeListeners: function() {
+ this.removeListeners_(this.target);
+ },
+
+ removeListeners_: function(node) {
+ var options = this.options;
+ if (options.attributes)
+ node.removeEventListener('DOMAttrModified', this, true);
+
+ if (options.characterData)
+ node.removeEventListener('DOMCharacterDataModified', this, true);
+
+ if (options.childList)
+ node.removeEventListener('DOMNodeInserted', this, true);
+
+ if (options.childList || options.subtree)
+ node.removeEventListener('DOMNodeRemoved', this, true);
+ },
+
+ /**
+ * Adds a transient observer on node. The transient observer gets removed
+ * next time we deliver the change records.
+ * @param {Node} node
+ */
+ addTransientObserver: function(node) {
+ // Don't add transient observers on the target itself. We already have all
+ // the required listeners set up on the target.
+ if (node === this.target)
+ return;
+
+ this.addListeners_(node);
+ this.transientObservedNodes.push(node);
+ var registrations = registrationsTable.get(node);
+ if (!registrations)
+ registrationsTable.set(node, registrations = []);
+
+ // We know that registrations does not contain this because we already
+ // checked if node === this.target.
+ registrations.push(this);
+ },
+
+ removeTransientObservers: function() {
+ var transientObservedNodes = this.transientObservedNodes;
+ this.transientObservedNodes = [];
+
+ transientObservedNodes.forEach(function(node) {
+ // Transient observers are never added to the target.
+ this.removeListeners_(node);
+
+ var registrations = registrationsTable.get(node);
+ for (var i = 0; i < registrations.length; i++) {
+ if (registrations[i] === this) {
+ registrations.splice(i, 1);
+ // Each node can only have one registered observer associated with
+ // this observer.
+ break;
+ }
+ }
+ }, this);
+ },
+
+ handleEvent: function(e) {
+ // Stop propagation since we are managing the propagation manually.
+ // This means that other mutation events on the page will not work
+ // correctly but that is by design.
+ e.stopImmediatePropagation();
+
+ switch (e.type) {
+ case 'DOMAttrModified':
+ // http://dom.spec.whatwg.org/#concept-mo-queue-attributes
+
+ var name = e.attrName;
+ var namespace = e.relatedNode.namespaceURI;
+ var target = e.target;
+
+ // 1.
+ var record = new getRecord('attributes', target);
+ record.attributeName = name;
+ record.attributeNamespace = namespace;
+
+ // 2.
+ var oldValue =
+ e.attrChange === MutationEvent.ADDITION ? null : e.prevValue;
+
+ forEachAncestorAndObserverEnqueueRecord(target, function(options) {
+ // 3.1, 4.2
+ if (!options.attributes)
+ return;
+
+ // 3.2, 4.3
+ if (options.attributeFilter && options.attributeFilter.length &&
+ options.attributeFilter.indexOf(name) === -1 &&
+ options.attributeFilter.indexOf(namespace) === -1) {
+ return;
+ }
+ // 3.3, 4.4
+ if (options.attributeOldValue)
+ return getRecordWithOldValue(oldValue);
+
+ // 3.4, 4.5
+ return record;
+ });
+
+ break;
+
+ case 'DOMCharacterDataModified':
+ // http://dom.spec.whatwg.org/#concept-mo-queue-characterdata
+ var target = e.target;
+
+ // 1.
+ var record = getRecord('characterData', target);
+
+ // 2.
+ var oldValue = e.prevValue;
+
+
+ forEachAncestorAndObserverEnqueueRecord(target, function(options) {
+ // 3.1, 4.2
+ if (!options.characterData)
+ return;
+
+ // 3.2, 4.3
+ if (options.characterDataOldValue)
+ return getRecordWithOldValue(oldValue);
+
+ // 3.3, 4.4
+ return record;
+ });
+
+ break;
+
+ case 'DOMNodeRemoved':
+ this.addTransientObserver(e.target);
+ // Fall through.
+ case 'DOMNodeInserted':
+ // http://dom.spec.whatwg.org/#concept-mo-queue-childlist
+ var target = e.relatedNode;
+ var changedNode = e.target;
+ var addedNodes, removedNodes;
+ if (e.type === 'DOMNodeInserted') {
+ addedNodes = [changedNode];
+ removedNodes = [];
+ } else {
+
+ addedNodes = [];
+ removedNodes = [changedNode];
+ }
+ var previousSibling = changedNode.previousSibling;
+ var nextSibling = changedNode.nextSibling;
+
+ // 1.
+ var record = getRecord('childList', target);
+ record.addedNodes = addedNodes;
+ record.removedNodes = removedNodes;
+ record.previousSibling = previousSibling;
+ record.nextSibling = nextSibling;
+
+ forEachAncestorAndObserverEnqueueRecord(target, function(options) {
+ // 2.1, 3.2
+ if (!options.childList)
+ return;
+
+ // 2.2, 3.3
+ return record;
+ });
+
+ }
+
+ clearRecords();
+ }
+ };
+
+ global.MutationObserver = MutationObserver;
+})(window);
+
+}
diff --git a/pkg/mutation_observer/lib/mutation_observer.min.js b/pkg/mutation_observer/lib/mutation_observer.min.js
new file mode 100644
index 0000000..1c25e0b
--- /dev/null
+++ b/pkg/mutation_observer/lib/mutation_observer.min.js
@@ -0,0 +1 @@
+if(!window.MutationObserver&&!window.WebKitMutationObserver){!function(global){var SideTable;if(typeof WeakMap!=="undefined"&&navigator.userAgent.indexOf("Firefox/")<0){SideTable=WeakMap}else{!function(){var defineProperty=Object.defineProperty;var hasOwnProperty=Object.hasOwnProperty;var counter=(new Date).getTime()%1e9;SideTable=function(){this.name="__st"+(Math.random()*1e9>>>0)+(counter++ +"__")};SideTable.prototype={set:function(key,value){defineProperty(key,this.name,{value:value,writable:true})},get:function(key){return hasOwnProperty.call(key,this.name)?key[this.name]:undefined},"delete":function(key){this.set(key,undefined)}}}()}var registrationsTable=new SideTable;var setImmediate=window.msSetImmediate;if(!setImmediate){var setImmediateQueue=[];var sentinel=String(Math.random());window.addEventListener("message",function(e){if(e.data===sentinel){var queue=setImmediateQueue;setImmediateQueue=[];queue.forEach(function(func){func()})}});setImmediate=function(func){setImmediateQueue.push(func);window.postMessage(sentinel,"*")}}var isScheduled=false;var scheduledObservers=[];function scheduleCallback(observer){scheduledObservers.push(observer);if(!isScheduled){isScheduled=true;setImmediate(dispatchCallbacks)}}function wrapIfNeeded(node){return window.ShadowDOMPolyfill&&window.ShadowDOMPolyfill.wrapIfNeeded(node)||node}function dispatchCallbacks(){isScheduled=false;var observers=scheduledObservers;scheduledObservers=[];observers.sort(function(o1,o2){return o1.uid_-o2.uid_});var anyNonEmpty=false;observers.forEach(function(observer){var queue=observer.takeRecords();removeTransientObserversFor(observer);if(queue.length){observer.callback_(queue,observer);anyNonEmpty=true}});if(anyNonEmpty)dispatchCallbacks()}function removeTransientObserversFor(observer){observer.nodes_.forEach(function(node){var registrations=registrationsTable.get(node);if(!registrations)return;registrations.forEach(function(registration){if(registration.observer===observer)registration.removeTransientObservers()})})}function forEachAncestorAndObserverEnqueueRecord(target,callback){for(var node=target;node;node=node.parentNode){var registrations=registrationsTable.get(node);if(registrations){for(var j=0;j<registrations.length;j++){var registration=registrations[j];var options=registration.options;if(node!==target&&!options.subtree)continue;var record=callback(options);if(record)registration.enqueue(record)}}}}var uidCounter=0;function MutationObserver(callback){this.callback_=callback;this.nodes_=[];this.records_=[];this.uid_=++uidCounter}MutationObserver.prototype={observe:function(target,options){target=wrapIfNeeded(target);if(!options.childList&&!options.attributes&&!options.characterData||options.attributeOldValue&&!options.attributes||options.attributeFilter&&options.attributeFilter.length&&!options.attributes||options.characterDataOldValue&&!options.characterData){throw new SyntaxError}var registrations=registrationsTable.get(target);if(!registrations)registrationsTable.set(target,registrations=[]);var registration;for(var i=0;i<registrations.length;i++){if(registrations[i].observer===this){registration=registrations[i];registration.removeListeners();registration.options=options;break}}if(!registration){registration=new Registration(this,target,options);registrations.push(registration);this.nodes_.push(target)}registration.addListeners()},disconnect:function(){this.nodes_.forEach(function(node){var registrations=registrationsTable.get(node);for(var i=0;i<registrations.length;i++){var registration=registrations[i];if(registration.observer===this){registration.removeListeners();registrations.splice(i,1);break}}},this);this.records_=[]},takeRecords:function(){var copyOfRecords=this.records_;this.records_=[];return copyOfRecords}};function MutationRecord(type,target){this.type=type;this.target=target;this.addedNodes=[];this.removedNodes=[];this.previousSibling=null;this.nextSibling=null;this.attributeName=null;this.attributeNamespace=null;this.oldValue=null}MutationObserver.prototype.constructor=MutationObserver;MutationObserver.name="MutationObserver";MutationRecord.prototype.constructor=MutationRecord;MutationRecord.name="MutationRecord";function copyMutationRecord(original){var record=new MutationRecord(original.type,original.target);record.addedNodes=original.addedNodes.slice();record.removedNodes=original.removedNodes.slice();record.previousSibling=original.previousSibling;record.nextSibling=original.nextSibling;record.attributeName=original.attributeName;record.attributeNamespace=original.attributeNamespace;record.oldValue=original.oldValue;return record}var currentRecord,recordWithOldValue;function getRecord(type,target){return currentRecord=new MutationRecord(type,target)}function getRecordWithOldValue(oldValue){if(recordWithOldValue)return recordWithOldValue;recordWithOldValue=copyMutationRecord(currentRecord);recordWithOldValue.oldValue=oldValue;return recordWithOldValue}function clearRecords(){currentRecord=recordWithOldValue=undefined}function recordRepresentsCurrentMutation(record){return record===recordWithOldValue||record===currentRecord}function selectRecord(lastRecord,newRecord){if(lastRecord===newRecord)return lastRecord;if(recordWithOldValue&&recordRepresentsCurrentMutation(lastRecord))return recordWithOldValue;return null}function Registration(observer,target,options){this.observer=observer;this.target=target;this.options=options;this.transientObservedNodes=[]}Registration.prototype={enqueue:function(record){var records=this.observer.records_;var length=records.length;if(records.length>0){var lastRecord=records[length-1];var recordToReplaceLast=selectRecord(lastRecord,record);if(recordToReplaceLast){records[length-1]=recordToReplaceLast;return}}else{scheduleCallback(this.observer)}records[length]=record},addListeners:function(){this.addListeners_(this.target)},addListeners_:function(node){var options=this.options;if(options.attributes)node.addEventListener("DOMAttrModified",this,true);if(options.characterData)node.addEventListener("DOMCharacterDataModified",this,true);if(options.childList)node.addEventListener("DOMNodeInserted",this,true);if(options.childList||options.subtree)node.addEventListener("DOMNodeRemoved",this,true)},removeListeners:function(){this.removeListeners_(this.target)},removeListeners_:function(node){var options=this.options;if(options.attributes)node.removeEventListener("DOMAttrModified",this,true);if(options.characterData)node.removeEventListener("DOMCharacterDataModified",this,true);if(options.childList)node.removeEventListener("DOMNodeInserted",this,true);if(options.childList||options.subtree)node.removeEventListener("DOMNodeRemoved",this,true)},addTransientObserver:function(node){if(node===this.target)return;this.addListeners_(node);this.transientObservedNodes.push(node);var registrations=registrationsTable.get(node);if(!registrations)registrationsTable.set(node,registrations=[]);registrations.push(this)},removeTransientObservers:function(){var transientObservedNodes=this.transientObservedNodes;this.transientObservedNodes=[];transientObservedNodes.forEach(function(node){this.removeListeners_(node);var registrations=registrationsTable.get(node);for(var i=0;i<registrations.length;i++){if(registrations[i]===this){registrations.splice(i,1);break}}},this)},handleEvent:function(e){e.stopImmediatePropagation();switch(e.type){case"DOMAttrModified":var name=e.attrName;var namespace=e.relatedNode.namespaceURI;var target=e.target;var record=new getRecord("attributes",target);record.attributeName=name;record.attributeNamespace=namespace;var oldValue=e.attrChange===MutationEvent.ADDITION?null:e.prevValue;forEachAncestorAndObserverEnqueueRecord(target,function(options){if(!options.attributes)return;if(options.attributeFilter&&options.attributeFilter.length&&options.attributeFilter.indexOf(name)===-1&&options.attributeFilter.indexOf(namespace)===-1){return}if(options.attributeOldValue)return getRecordWithOldValue(oldValue);return record});break;case"DOMCharacterDataModified":var target=e.target;var record=getRecord("characterData",target);var oldValue=e.prevValue;forEachAncestorAndObserverEnqueueRecord(target,function(options){if(!options.characterData)return;if(options.characterDataOldValue)return getRecordWithOldValue(oldValue);return record});break;case"DOMNodeRemoved":this.addTransientObserver(e.target);case"DOMNodeInserted":var target=e.relatedNode;var changedNode=e.target;var addedNodes,removedNodes;if(e.type==="DOMNodeInserted"){addedNodes=[changedNode];removedNodes=[]}else{addedNodes=[];removedNodes=[changedNode]}var previousSibling=changedNode.previousSibling;var nextSibling=changedNode.nextSibling;var record=getRecord("childList",target);record.addedNodes=addedNodes;record.removedNodes=removedNodes;record.previousSibling=previousSibling;record.nextSibling=nextSibling;forEachAncestorAndObserverEnqueueRecord(target,function(options){if(!options.childList)return;return record})}clearRecords()}};global.MutationObserver=MutationObserver}(window)}
\ No newline at end of file
diff --git a/pkg/mutation_observer/pubspec.yaml b/pkg/mutation_observer/pubspec.yaml
new file mode 100644
index 0000000..cafca55
--- /dev/null
+++ b/pkg/mutation_observer/pubspec.yaml
@@ -0,0 +1,8 @@
+name: mutation_observer
+author: "Web UI Team <web-ui-dev@dartlang.org>"
+homepage: https://code.google.com/p/dart/source/browse/branches/bleeding_edge/dart/pkg/mutation_observer/
+documentation: https://api.dartlang.org/docs/releases/latest/dart_html/MutationObserver.html
+description: >
+ Mutation Observers provide a way to react to changes in the DOM.
+dev_dependencies:
+ unittest: any
diff --git a/pkg/mutation_observer/test/mutation_observer_test.dart b/pkg/mutation_observer/test/mutation_observer_test.dart
new file mode 100644
index 0000000..c4c84e3e4
--- /dev/null
+++ b/pkg/mutation_observer/test/mutation_observer_test.dart
@@ -0,0 +1,114 @@
+// Copyright (c) 2013, 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 mutation_observer_test;
+
+import 'dart:html';
+import 'package:unittest/unittest.dart';
+import 'package:unittest/html_config.dart';
+
+main() {
+ useHtmlConfiguration();
+
+ // Load the MutationObserver polyfill.
+ HttpRequest.getString('/root_dart/pkg/mutation_observer/lib/'
+ 'mutation_observer.min.js').then((code) {
+
+ // Force MutationObserver polyfill to be used so we can test it, even in
+ // browsers with native support.
+ document.head.children.add(new ScriptElement()
+ ..text = 'window.MutationObserver = void 0;'
+ 'window.WebKitMutationObserver = void 0;'
+ '$code');
+
+ testMutationObserver();
+ });
+}
+
+/**
+ * Test suite for Mutation Observers. This is just a small set of sanity
+ * checks, not a complete test suite.
+ */
+testMutationObserver() {
+ group('supported', () {
+ test('supported', () {
+ expect(MutationObserver.supported, true, reason: 'polyfill loaded.');
+ });
+ });
+
+ group('childList', () {
+ mutationCallback(count, expectation) {
+ var done = false;
+ var nodes = [];
+
+ callback(mutations, observer) {
+ for (MutationRecord mutation in mutations) {
+ for (Node node in mutation.addedNodes) {
+ nodes.add(node);
+ }
+ }
+ if (nodes.length >= count) {
+ done = true;
+ expect(nodes.length, count);
+ expect(nodes, expectation);
+ }
+ }
+
+ return expectAsyncUntil2(callback, () => done);
+ }
+
+ test('empty options is syntax error', () {
+ var mutationObserver = new MutationObserver(
+ (mutations, observer) { expect(false, isTrue,
+ reason: 'Should not be reached'); });
+ expect(() { mutationObserver.observe(document, {}); },
+ throws);
+ });
+
+ test('direct-parallel options-named', () {
+ var container = new DivElement();
+ var div1 = new DivElement();
+ var div2 = new DivElement();
+ var mutationObserver = new MutationObserver(
+ mutationCallback(2, orderedEquals([div1, div2])));
+ mutationObserver.observe(container, childList: true);
+
+ container.append(div1);
+ container.append(div2);
+ });
+
+ test('direct-nested options-named', () {
+ var container = new DivElement();
+ var div1 = new DivElement();
+ var div2 = new DivElement();
+ var mutationObserver =
+ new MutationObserver(mutationCallback(1, orderedEquals([div1])));
+ mutationObserver.observe(container, childList: true);
+
+ container.append(div1);
+ div1.append(div2);
+ });
+
+ test('subtree options-named', () {
+ var container = new DivElement();
+ var div1 = new DivElement();
+ var div2 = new DivElement();
+ var mutationObserver = new MutationObserver(
+ mutationCallback(2, orderedEquals([div1, div2])));
+ mutationObserver.observe(container, childList: true, subtree: true);
+
+ container.append(div1);
+ div1.append(div2);
+ });
+
+ test('mutation event', () {
+ var event = new MutationEvent('something', prevValue: 'prev',
+ newValue: 'new', attrName: 'attr');
+ expect(event is MutationEvent, isTrue);
+ expect(event.prevValue, 'prev');
+ expect(event.newValue, 'new');
+ expect(event.attrName, 'attr');
+ });
+ });
+}
diff --git a/pkg/observe/lib/src/compound_binding.dart b/pkg/observe/lib/src/compound_binding.dart
index 625c82c..94db67a8 100644
--- a/pkg/observe/lib/src/compound_binding.dart
+++ b/pkg/observe/lib/src/compound_binding.dart
@@ -34,9 +34,22 @@
// use integers.
Map<dynamic, StreamSubscription> _observers = new Map();
Map _values = new Map();
- bool _scheduled = false;
Object _value;
+ /**
+ * True if [resolve] is scheduled. You can set this to true if you plan to
+ * call [resolve] manually, avoiding the need for scheduling an asynchronous
+ * resolve.
+ */
+ // TODO(jmesserly): I don't like having this public, is the optimization
+ // really needed? "runAsync" in Dart should be pretty cheap.
+ bool scheduled = false;
+
+ /**
+ * Creates a new CompoundBinding, optionally proving the [combinator] function
+ * for computing the value. You can also set [schedule] to true if you plan
+ * to invoke [resolve] manually after initial construction of the binding.
+ */
CompoundBinding([CompoundBindingCombinator combinator]) {
// TODO(jmesserly): this is a tweak to the original code, it seemed to me
// that passing the combinator to the constructor should be equivalent to
@@ -86,14 +99,14 @@
// TODO(rafaelw): Consider having a seperate ChangeSummary for
// CompoundBindings so to excess dirtyChecks.
void _scheduleResolve() {
- if (_scheduled) return;
- _scheduled = true;
+ if (scheduled) return;
+ scheduled = true;
runAsync(resolve);
}
void resolve() {
if (_observers.isEmpty) return;
- _scheduled = false;
+ scheduled = false;
if (_combinator == null) {
throw new StateError(
diff --git a/pkg/observe/lib/src/observable.dart b/pkg/observe/lib/src/observable.dart
index a49f8f1..7610a0f 100644
--- a/pkg/observe/lib/src/observable.dart
+++ b/pkg/observe/lib/src/observable.dart
@@ -63,6 +63,12 @@
void notifyChange(ChangeRecord record);
/**
+ * True if this object has any observers, and should call
+ * [notifyChange] for changes.
+ */
+ bool get hasObservers;
+
+ /**
* Performs dirty checking of objects that inherit from [ObservableMixin].
* This scans all observed objects using mirrors and determines if any fields
* have changed. If they have, it delivers the changes for the object.
@@ -99,10 +105,6 @@
return _changes.stream;
}
- /**
- * True if this object has any observers, and should call
- * [notifyPropertyChange] for changes.
- */
bool get hasObservers => _changes != null && _changes.hasListener;
void _observed() {
diff --git a/pkg/observe/lib/src/observable_map.dart b/pkg/observe/lib/src/observable_map.dart
index 2cd64d5..621c86f 100644
--- a/pkg/observe/lib/src/observable_map.dart
+++ b/pkg/observe/lib/src/observable_map.dart
@@ -67,9 +67,7 @@
* you should use [toObservable].
*/
factory ObservableMap.from(Map<K, V> other) {
- var result = new ObservableMap<K, V>._createFromType(other);
- other.forEach((key, value) { result[key] = value; });
- return result;
+ return new ObservableMap<K, V>._createFromType(other)..addAll(other);
}
factory ObservableMap._createFromType(Map<K, V> other) {
@@ -114,6 +112,10 @@
}
}
+ void addAll(Map<K, V> other) {
+ other.forEach((K key, V value) { this[key] = value; });
+ }
+
V putIfAbsent(K key, V ifAbsent()) {
int len = _map.length;
V result = _map.putIfAbsent(key, ifAbsent);
diff --git a/pkg/observe/test/list_change_test.dart b/pkg/observe/test/list_change_test.dart
index ae433d1..8f44357 100644
--- a/pkg/observe/test/list_change_test.dart
+++ b/pkg/observe/test/list_change_test.dart
@@ -76,7 +76,7 @@
}
// Note: compare strings for easier debugging.
- expect('$copy', '$model', reason: '!!! summary $summary');
+ expect('$copy', '$model', reason: 'summary $summary');
}
observeTest('Contained', () {
diff --git a/pkg/observe/test/observe_test.dart b/pkg/observe/test/observe_test.dart
index c898e43..8b07d4b 100644
--- a/pkg/observe/test/observe_test.dart
+++ b/pkg/observe/test/observe_test.dart
@@ -9,6 +9,9 @@
import 'package:unittest/unittest.dart';
import 'observe_test_utils.dart';
+// Note: this ensures we run the dartanalyzer on the @observe package.
+// @static-clean
+
const _VALUE = const Symbol('value');
main() {
diff --git a/pkg/path/lib/path.dart b/pkg/path/lib/path.dart
index 95bc90d..eb126d5 100644
--- a/pkg/path/lib/path.dart
+++ b/pkg/path/lib/path.dart
@@ -55,10 +55,17 @@
/// functional interface and not require users to create one.
final _builder = new Builder();
-/**
- * Inserts [length] elements in front of the [list] and fills them with the
- * [fillValue].
- */
+/// A default builder for manipulating POSIX paths.
+final posix = new Builder(style: Style.posix);
+
+/// A default builder for manipulating Windows paths.
+final windows = new Builder(style: Style.windows);
+
+/// A default builder for manipulating URLs.
+final url = new Builder(style: Style.url);
+
+/// Inserts [length] elements in front of the [list] and fills them with the
+/// [fillValue].
void _growListFront(List list, int length, fillValue) =>
list.insertAll(0, new List.filled(length, fillValue));
@@ -376,25 +383,22 @@
/// Creates a new path builder for the given style and root directory.
///
/// If [style] is omitted, it uses the host operating system's path style. If
- /// [root] is omitted, it defaults to the current working directory. If [root]
- /// is relative, it is considered relative to the current working directory.
+ /// only [root] is omitted, it defaults ".". If *both* [style] and [root] are
+ /// omitted, [root] defaults to the current working directory.
///
/// On the browser, the path style is [Style.url]. In Dartium, [root] defaults
/// to the current URL. When using dart2js, it currently defaults to `.` due
/// to technical constraints.
factory Builder({Style style, String root}) {
- if (style == null) {
- if (_io == null) {
- style = Style.url;
- } else if (_io.classes[const Symbol('Platform')]
- .getField(const Symbol('operatingSystem')).reflectee == 'windows') {
- style = Style.windows;
+ if (root == null) {
+ if (style == null) {
+ root = current;
} else {
- style = Style.posix;
+ root = ".";
}
}
- if (root == null) root = current;
+ if (style == null) style = Style.platform;
return new Builder._(style, root);
}
@@ -855,6 +859,24 @@
/// `file://`) or with "/".
static final url = new _UrlStyle();
+ /// The style of the host platform.
+ ///
+ /// When running on the command line, this will be [windows] or [posix] based
+ /// on the host operating system. On a browser, this will be [url].
+ static final platform = _getPlatformStyle();
+
+ /// Gets the type of the host platform.
+ static Style _getPlatformStyle() {
+ if (_io == null) return Style.url;
+
+ if (_io.classes[const Symbol('Platform')]
+ .getField(const Symbol('operatingSystem')).reflectee == 'windows') {
+ return Style.windows;
+ }
+
+ return Style.posix;
+ }
+
/// The name of this path style. Will be "posix" or "windows".
String get name;
diff --git a/pkg/path/test/browser_test.dart b/pkg/path/test/browser_test.dart
index 2a830c7..0725646 100644
--- a/pkg/path/test/browser_test.dart
+++ b/pkg/path/test/browser_test.dart
@@ -12,15 +12,24 @@
useHtmlConfiguration();
group('new Builder()', () {
- test('uses the current working directory if root is omitted', () {
+ test('uses the window location if root and style are omitted', () {
var builder = new path.Builder();
expect(builder.root, window.location.href);
});
- test('uses URL if style is omitted', () {
- var builder = new path.Builder();
- expect(builder.style, path.Style.url);
+ test('uses "." if root is omitted', () {
+ var builder = new path.Builder(style: path.Style.platform);
+ expect(builder.root, ".");
});
+
+ test('uses the host platform if style is omitted', () {
+ var builder = new path.Builder();
+ expect(builder.style, path.Style.platform);
+ });
+ });
+
+ test('Style.platform is url', () {
+ expect(path.Style.platform, path.Style.url);
});
test('current', () {
diff --git a/pkg/path/test/io_test.dart b/pkg/path/test/io_test.dart
index fc29ced..6651249 100644
--- a/pkg/path/test/io_test.dart
+++ b/pkg/path/test/io_test.dart
@@ -9,19 +9,28 @@
main() {
group('new Builder()', () {
- test('uses the current working directory if root is omitted', () {
+ test('uses the current directory if root and style are omitted', () {
var builder = new path.Builder();
expect(builder.root, io.Directory.current.path);
});
- test('uses the host OS if style is omitted', () {
- var builder = new path.Builder();
- if (io.Platform.operatingSystem == 'windows') {
- expect(builder.style, path.Style.windows);
- } else {
- expect(builder.style, path.Style.posix);
- }
+ test('uses "." if root is omitted', () {
+ var builder = new path.Builder(style: path.Style.platform);
+ expect(builder.root, ".");
});
+
+ test('uses the host platform if style is omitted', () {
+ var builder = new path.Builder();
+ expect(builder.style, path.Style.platform);
+ });
+ });
+
+ test('Style.platform returns the host platform style', () {
+ if (io.Platform.operatingSystem == 'windows') {
+ expect(path.Style.platform, path.Style.windows);
+ } else {
+ expect(path.Style.platform, path.Style.posix);
+ }
});
test('current', () {
diff --git a/pkg/path/test/path_test.dart b/pkg/path/test/path_test.dart
index ef3cf21e..d6c2f34 100644
--- a/pkg/path/test/path_test.dart
+++ b/pkg/path/test/path_test.dart
@@ -34,4 +34,19 @@
expect(builder.style, path.Style.windows);
});
});
+
+ test('posix is a default Builder for the POSIX style', () {
+ expect(path.posix.style, path.Style.posix);
+ expect(path.posix.root, ".");
+ });
+
+ test('windows is a default Builder for the Windows style', () {
+ expect(path.windows.style, path.Style.windows);
+ expect(path.windows.root, ".");
+ });
+
+ test('url is a default Builder for the URL style', () {
+ expect(path.url.style, path.Style.url);
+ expect(path.url.root, ".");
+ });
}
diff --git a/pkg/pkg.status b/pkg/pkg.status
index c8d7b4d..4a3e6b8 100644
--- a/pkg/pkg.status
+++ b/pkg/pkg.status
@@ -17,15 +17,10 @@
[ $runtime == vm ]
watcher/test/no_subscription_test: Pass, Fail # Issue 12107
-
-[ $compiler == none && $runtime == drt && $mode == debug]
-mdv/test/custom_element_bindings_test: Fail # Issue 11657
-
-[ $compiler == dart2js && $runtime == ff ]
-unittest/test/unittest_test: Pass, Timeout # http://dartbug.com/11473
+watcher/test/directory_watcher_test: Pass, Fail # Issue 12107
[ $runtime == d8 || $runtime == jsshell ]
-unittest/test/unittest_test: Pass, Fail # http://dartbug.com/10109
+unittest/test/unittest_nested_groups_setup_teardown_test: Pass, Fail # http://dartbug.com/10109
stack_trace/test/vm_test: Fail, OK # VM-specific traces
sequence_zip/test/stream_test: Fail, OK # Timers are not supported.
@@ -72,14 +67,16 @@
unittest/test/mock_stepwise_negative_test: Skip
[ $compiler == dart2js && $csp ]
-unittest/test/unittest_test: Pass, Crash # Issue 10935
+unittest/test/mirror_matchers_test: Skip # Issue 12151
observe/test/observe_test: Fail # Issue 11970
observe/test/path_observer_test: Fail # Issue 11970
mdv/test/binding_syntax_test: Fail # Issue 11970
-
serialization/test/serialization_test: Fail # Issue 6490
serialization/test/no_library_test: Fail # Issue 6490
+# This test cannot run under CSP because it is injecting a JavaScript polyfill
+mutation_observer: Skip
+
[ $compiler == dart2js && $minified ]
# The unminified unittest tests test that the real names of Dart types are
# printed. Minified versions of these tests exist that test the behavior when
@@ -140,6 +137,7 @@
scheduled_test/test/scheduled_test/wrap_async_test: Fail # http://dartbug.com/8440
scheduled_test/test/scheduled_test/wrap_future_test: Fail # http://dartbug.com/8440
+*/test/analyzer_test: Skip # No need to run analysis tests on browser bots
[ $runtime == safari]
# Bug in JSC: the test only passes when being debugged.
@@ -170,10 +168,13 @@
# test on Dartium, which requires all tests to have a library.
[ $runtime == dartium || $runtime == drt ]
serialization/test/no_library_test: Skip # Expected Failure
+mdv/test/template_element_test: Pass, Fail # Issue 12177
-# Skip mdv tests on command line VM, they only run in the browser.
+# Skip tests on the VM if the package depends on dart:html
[ $runtime == vm ]
+custom_element: Skip
mdv: Skip
+mutation_observer: Skip
[ $runtime == safari || $runtime == chrome || $runtime == ie9 || $runtime == ff || $runtime == dartium || $runtime == drt ]
docgen/test/single_library_test: Skip # Uses dart:io
diff --git a/pkg/unittest/lib/interactive_html_config.dart b/pkg/unittest/lib/interactive_html_config.dart
index b962e1e..4f5dccd 100644
--- a/pkg/unittest/lib/interactive_html_config.dart
+++ b/pkg/unittest/lib/interactive_html_config.dart
@@ -19,6 +19,7 @@
import 'dart:html';
import 'dart:async';
+import 'dart:json' as json;
import 'dart:math';
import 'package:stack_trace/stack_trace.dart';
@@ -165,7 +166,7 @@
int elapsed = end.difference(_testStarts[testCase.id]).inMilliseconds;
if (testCase.stackTrace != null) {
var message = json.stringify(testCase.stackTrace.frames.map((frame) {
- return <String>{
+ return <String, dynamic>{
"uri": frame.uri.toString(),
"line": frame.line,
"column": frame.column,
diff --git a/pkg/unittest/lib/mirror_matchers.dart b/pkg/unittest/lib/mirror_matchers.dart
new file mode 100644
index 0000000..7e91529
--- /dev/null
+++ b/pkg/unittest/lib/mirror_matchers.dart
@@ -0,0 +1,92 @@
+// Copyright (c) 2013, 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.
+/**
+ * The mirror matchers library provides some additional matchers that
+ * make use of dart:mirrors.
+ *
+ * ## Installing ##
+ *
+ * Use [pub][] to install this package. Add the following to your `pubspec.yaml`
+ * file.
+ *
+ * dependencies:
+ * unittest: any
+ *
+ * Then run `pub install`.
+ *
+ * Import this into your Dart code with:
+ *
+ * import 'package:unittest/mirror_matchers.dart';
+ *
+ * For more information, see the [unittest package on pub.dartlang.org].
+ * (http://pub.dartlang.org/packages/unittest).
+ *
+ * [pub]: http://pub.dartlang.org
+ * [pkg]: http://pub.dartlang.org/packages/mirror_matchers
+ */
+library mirror_matchers;
+
+import 'dart:async';
+import 'dart:mirrors';
+import 'package:meta/meta.dart';
+
+import 'matcher.dart';
+
+/**
+ * Returns a matcher that checks if a class instance has a property
+ * with name [name], and optionally, if that property in turn satisfies
+ * a [matcher].
+ */
+Matcher hasProperty(String name, [matcher]) =>
+ new _HasProperty(name, matcher == null ? null : wrapMatcher(matcher));
+
+class _HasProperty extends Matcher {
+ final String _name;
+ final Matcher _matcher;
+
+ const _HasProperty(this._name, [this._matcher]);
+
+ bool matches(item, Map matchState) {
+ var mirror = reflect(item);
+ var classMirror = mirror.type;
+ var symbol = new Symbol(_name);
+ if (!classMirror.getters.containsKey(symbol)) {
+ addStateInfo(matchState, {'reason': 'has no property named "$_name"'});
+ return false;
+ }
+ if (_matcher == null) return true;
+ var result = mirror.getField(symbol);
+ var resultMatches = _matcher.matches(result.reflectee, matchState);
+ if (!resultMatches) {
+ addStateInfo(matchState, {'value': result.reflectee});
+ }
+ return resultMatches;
+ }
+
+ Description describe(Description description) {
+ description.add('has property "$_name"');
+ if (_matcher != null) {
+ description.add(' which matches ').addDescriptionOf(_matcher);
+ }
+ return description;
+ }
+
+ Description describeMismatch(item, Description mismatchDescription,
+ Map matchState, bool verbose) {
+ var reason = matchState == null ? null : matchState['reason'];
+ if (reason != null) {
+ mismatchDescription.add(reason);
+ } else {
+ mismatchDescription.add('has property "$_name" with value ').
+ addDescriptionOf(matchState['value']);
+ var innerDescription = new StringDescription();
+ _matcher.describeMismatch(matchState['value'], innerDescription,
+ matchState['state'], verbose);
+ if (innerDescription.length > 0) {
+ mismatchDescription.add(' which ').add(innerDescription.toString());
+ }
+ }
+ return mismatchDescription;
+ }
+}
diff --git a/pkg/unittest/lib/src/core_matchers.dart b/pkg/unittest/lib/src/core_matchers.dart
index 3d10f6d..b9bde13 100644
--- a/pkg/unittest/lib/src/core_matchers.dart
+++ b/pkg/unittest/lib/src/core_matchers.dart
@@ -849,13 +849,8 @@
* have a Widget class where each Widget has a price; we could make a
* [CustomMatcher] that can make assertions about prices with:
*
-<<<<<<< .mine
* class HasPrice extends CustomMatcher {
* const HasPrice(matcher) :
-=======
- * class HasPrice extends CustomMatcher {
- * HasPrice(matcher) :
->>>>>>> .r25321
* super("Widget with price that is", "price", matcher);
* featureValueOf(actual) => actual.price;
* }
@@ -898,4 +893,3 @@
return mismatchDescription;
}
}
-
diff --git a/pkg/unittest/pubspec.yaml b/pkg/unittest/pubspec.yaml
index ecaba6d..aa32b1d 100644
--- a/pkg/unittest/pubspec.yaml
+++ b/pkg/unittest/pubspec.yaml
@@ -1,9 +1,9 @@
name: unittest
-author: "Dart Team <misc@dartlang.org>"
+author: Dart Team <misc@dartlang.org>
+description: A library for writing dart unit tests.
homepage: http://www.dartlang.org
documentation: http://api.dartlang.org/docs/pkg/unittest
-description: >
- A library for writing dart unit tests.
dependencies:
+ json: any
meta: any
stack_trace: any
diff --git a/pkg/unittest/test/matchers_test.dart b/pkg/unittest/test/matchers_test.dart
index 6f4338c..b78ee47 100644
--- a/pkg/unittest/test/matchers_test.dart
+++ b/pkg/unittest/test/matchers_test.dart
@@ -203,7 +203,7 @@
test('isZero', () {
shouldPass(0, isZero);
- shouldFail(1, isZero,
+ shouldFail(1, isZero,
"Expected: a value equal to <0> "
"Actual: <1> "
"Which: is not a value equal to <0>");
@@ -222,7 +222,7 @@
"Expected: a positive value "
"Actual: <-1> "
"Which: is not a positive value");
- shouldFail(0, isPositive,
+ shouldFail(0, isPositive,
"Expected: a positive value "
"Actual: <0> "
"Which: is not a positive value");
@@ -428,7 +428,7 @@
"Which: has value ['foo', 'bar'] which has value 'bar' "
"which is different. Expected: foo Actual: bar ^ "
"Differ at offset 0 at index 1 at index 0");
- shouldFail(d, everyElement(allOf(hasLength(greaterThan(0)),
+ shouldFail(d, everyElement(allOf(hasLength(greaterThan(0)),
contains('foo'))),
"Expected: every element((an object with length of a value "
"greater than <0> and contains 'foo')) "
@@ -759,7 +759,7 @@
print(foo);
}
}
-
+
abstract class Abstraction {
void norealization();
}
diff --git a/pkg/unittest/test/mirror_matchers_test.dart b/pkg/unittest/test/mirror_matchers_test.dart
new file mode 100644
index 0000000..22e011c
--- /dev/null
+++ b/pkg/unittest/test/mirror_matchers_test.dart
@@ -0,0 +1,29 @@
+// Copyright (c) 2012, 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 'dart:async';
+import 'dart:collection';
+
+import 'package:unittest/unittest.dart';
+import 'package:unittest/mirror_matchers.dart';
+
+import 'test_common.dart';
+import 'test_utils.dart';
+
+void main() {
+
+ initUtils();
+
+ test('hasProperty', () {
+ var foo = [3];
+ shouldPass(foo, hasProperty('length', 1));
+ shouldFail(foo, hasProperty('foo'), 'Expected: has property "foo" '
+ 'Actual: [3] '
+ 'Which: has no property named "foo"');
+ shouldFail(foo, hasProperty('length', 2),
+ 'Expected: has property "length" which matches <2> '
+ 'Actual: [3] '
+ 'Which: has property "length" with value <1>');
+ });
+}
\ No newline at end of file
diff --git a/pkg/unittest/test/unittest_async_exception_test.dart b/pkg/unittest/test/unittest_async_exception_test.dart
new file mode 100644
index 0000000..34298b7
--- /dev/null
+++ b/pkg/unittest/test/unittest_async_exception_test.dart
@@ -0,0 +1,21 @@
+// Copyright (c) 2013, 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 unittestTest;
+import 'dart:isolate';
+import 'dart:async';
+import 'package:unittest/unittest.dart';
+
+part 'unittest_test_utils.dart';
+
+var testName = 'async exception test';
+
+var testFunction = (_) {
+ test(testName, () {
+ expectAsync0(() {});
+ _defer(() => guardAsync(() { throw "error!"; }));
+ });
+};
+
+var expected = buildStatusString(0, 1, 0, testName, message: 'Caught error!');
diff --git a/pkg/unittest/test/unittest_async_setup_teardown_test.dart b/pkg/unittest/test/unittest_async_setup_teardown_test.dart
new file mode 100644
index 0000000..a73efc8
--- /dev/null
+++ b/pkg/unittest/test/unittest_async_setup_teardown_test.dart
@@ -0,0 +1,64 @@
+// Copyright (c) 2013, 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 unittestTest;
+import 'dart:isolate';
+import 'dart:async';
+import 'package:unittest/unittest.dart';
+
+part 'unittest_test_utils.dart';
+
+var testName = 'async setup teardown test';
+
+var testFunction = (_) {
+ group('good setup/good teardown', () {
+ setUp(() {
+ return new Future.value(0);
+ });
+ tearDown(() {
+ return new Future.value(0);
+ });
+ test('foo1', (){});
+ });
+ group('good setup/bad teardown', () {
+ setUp(() {
+ return new Future.value(0);
+ });
+ tearDown(() {
+ return new Future.error("Failed to complete tearDown");
+ });
+ test('foo2', (){});
+ });
+ group('bad setup/good teardown', () {
+ setUp(() {
+ return new Future.error("Failed to complete setUp");
+ });
+ tearDown(() {
+ return new Future.value(0);
+ });
+ test('foo3', (){});
+ });
+ group('bad setup/bad teardown', () {
+ setUp(() {
+ return new Future.error("Failed to complete setUp");
+ });
+ tearDown(() {
+ return new Future.error("Failed to complete tearDown");
+ });
+ test('foo4', (){});
+ });
+ // The next test is just to make sure we make steady progress
+ // through the tests.
+ test('post groups', () {});
+};
+
+var expected = buildStatusString(2, 0, 3,
+ 'good setup/good teardown foo1::'
+ 'good setup/bad teardown foo2:'
+ 'Teardown failed: Caught Failed to complete tearDown:'
+ 'bad setup/good teardown foo3:'
+ 'Setup failed: Caught Failed to complete setUp:'
+ 'bad setup/bad teardown foo4:'
+ 'Setup failed: Caught Failed to complete setUp:'
+ 'post groups');
diff --git a/pkg/unittest/test/unittest_completion_test.dart b/pkg/unittest/test/unittest_completion_test.dart
new file mode 100644
index 0000000..97fa9d0
--- /dev/null
+++ b/pkg/unittest/test/unittest_completion_test.dart
@@ -0,0 +1,27 @@
+// Copyright (c) 2013, 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 unittestTest;
+import 'dart:isolate';
+import 'dart:async';
+import 'package:unittest/unittest.dart';
+
+part 'unittest_test_utils.dart';
+
+var testName = 'completion test';
+
+var testFunction = (TestConfiguration testConfig) {
+ test(testName, () {
+ var _callback;
+ _callback = expectAsyncUntil0(() {
+ if (++testConfig.count < 10) {
+ _defer(_callback);
+ }
+ },
+ () => (testConfig.count == 10));
+ _defer(_callback);
+ });
+};
+
+var expected = buildStatusString(1, 0, 0, testName, count: 10);
diff --git a/pkg/unittest/test/unittest_correct_callback_test.dart b/pkg/unittest/test/unittest_correct_callback_test.dart
new file mode 100644
index 0000000..cd52ba0
--- /dev/null
+++ b/pkg/unittest/test/unittest_correct_callback_test.dart
@@ -0,0 +1,19 @@
+// Copyright (c) 2013, 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 unittestTest;
+import 'dart:isolate';
+import 'dart:async';
+import 'package:unittest/unittest.dart';
+
+part 'unittest_test_utils.dart';
+
+var testName = 'correct callback test';
+
+var testFunction = (TestConfiguration testConfig) {
+ test(testName,
+ () =>_defer(expectAsync0((){ ++testConfig.count;})));
+};
+
+var expected = buildStatusString(1, 0, 0, testName, count: 1);
diff --git a/pkg/unittest/test/unittest_exception_test.dart b/pkg/unittest/test/unittest_exception_test.dart
new file mode 100644
index 0000000..23d302d
--- /dev/null
+++ b/pkg/unittest/test/unittest_exception_test.dart
@@ -0,0 +1,19 @@
+// Copyright (c) 2013, 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 unittestTest;
+import 'dart:isolate';
+import 'dart:async';
+import 'package:unittest/unittest.dart';
+
+part 'unittest_test_utils.dart';
+
+var testName = 'exception test';
+
+var testFunction = (_) {
+ test(testName, () { throw new Exception('Fail.'); });
+};
+
+var expected = buildStatusString(0, 0, 1, testName,
+ message: 'Test failed: Caught Exception: Fail.');
diff --git a/pkg/unittest/test/unittest_excess_callback_test.dart b/pkg/unittest/test/unittest_excess_callback_test.dart
new file mode 100644
index 0000000..f3876b5
--- /dev/null
+++ b/pkg/unittest/test/unittest_excess_callback_test.dart
@@ -0,0 +1,28 @@
+// Copyright (c) 2013, 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 unittestTest;
+import 'dart:isolate';
+import 'dart:async';
+import 'package:unittest/unittest.dart';
+
+part 'unittest_test_utils.dart';
+
+var testName = 'excess callback test';
+
+var testFunction = (TestConfiguration testConfig) {
+ test(testName, () {
+ var _callback0 = expectAsync0(() => ++testConfig.count);
+ var _callback1 = expectAsync0(() => ++testConfig.count);
+ var _callback2 = expectAsync0(() {
+ _callback1();
+ _callback1();
+ _callback0();
+ });
+ _defer(_callback2);
+ });
+};
+
+var expected = buildStatusString(0, 1, 0, testName,
+ count: 1, message: 'Callback called more times than expected (1).');
diff --git a/pkg/unittest/test/unittest_late_exception_test.dart b/pkg/unittest/test/unittest_late_exception_test.dart
new file mode 100644
index 0000000..7a5c3e6
--- /dev/null
+++ b/pkg/unittest/test/unittest_late_exception_test.dart
@@ -0,0 +1,27 @@
+// Copyright (c) 2013, 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 unittestTest;
+import 'dart:isolate';
+import 'dart:async';
+import 'package:unittest/unittest.dart';
+
+part 'unittest_test_utils.dart';
+
+var testName = 'late exception test';
+
+var testFunction = (_) {
+ var f;
+ test('testOne', () {
+ f = expectAsync0(() {});
+ _defer(f);
+ });
+ test('testTwo', () {
+ _defer(expectAsync0(() { f(); }));
+ });
+};
+
+var expected = buildStatusString(1, 0, 1, 'testOne',
+ message: 'Callback called (2) after test case testOne has already '
+ 'been marked as pass.:testTwo:');
diff --git a/pkg/unittest/test/unittest_middle_exception_test.dart b/pkg/unittest/test/unittest_middle_exception_test.dart
new file mode 100644
index 0000000..d405500
--- /dev/null
+++ b/pkg/unittest/test/unittest_middle_exception_test.dart
@@ -0,0 +1,27 @@
+// Copyright (c) 2013, 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 unittestTest;
+import 'dart:isolate';
+import 'dart:async';
+import 'package:unittest/unittest.dart';
+
+part 'unittest_test_utils.dart';
+
+var testName = 'late exception test';
+
+var testFunction = (_) {
+ test('testOne', () { expect(true, isTrue); });
+ test('testTwo', () { expect(true, isFalse); });
+ test('testThree', () {
+ var done = expectAsync0((){});
+ _defer(() {
+ expect(true, isTrue);
+ done();
+ });
+ });
+};
+
+var expected = buildStatusString(2, 1, 0,
+ 'testOne::testTwo:Expected: false Actual: <true>:testThree');
diff --git a/pkg/unittest/test/unittest_nested_groups_setup_teardown_test.dart b/pkg/unittest/test/unittest_nested_groups_setup_teardown_test.dart
new file mode 100644
index 0000000..1cb16a0
--- /dev/null
+++ b/pkg/unittest/test/unittest_nested_groups_setup_teardown_test.dart
@@ -0,0 +1,43 @@
+// Copyright (c) 2013, 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 unittestTest;
+import 'dart:isolate';
+import 'dart:async';
+import 'package:unittest/unittest.dart';
+
+part 'unittest_test_utils.dart';
+
+var testName = 'nested groups setup/teardown';
+
+var testFunction = (_) {
+ StringBuffer s = new StringBuffer();
+ group('level 1', () {
+ setUp(makeDelayedSetup(1, s));
+ group('level 2', () {
+ setUp(makeImmediateSetup(2, s));
+ tearDown(makeDelayedTeardown(2, s));
+ group('level 3', () {
+ group('level 4', () {
+ setUp(makeDelayedSetup(4, s));
+ tearDown(makeImmediateTeardown(4, s));
+ group('level 5', () {
+ setUp(makeImmediateSetup(5, s));
+ group('level 6', () {
+ tearDown(makeDelayedTeardown(6, s));
+ test('inner', () {});
+ });
+ });
+ });
+ });
+ });
+ });
+ test('after nest', () {
+ expect(s.toString(), "l1 U l2 U l4 U l5 U l6 D l4 D l2 D ");
+ });
+};
+
+var expected = buildStatusString(2, 0, 0,
+ 'level 1 level 2 level 3 level 4 level 5 level 6 inner::'
+ 'after nest');
diff --git a/pkg/unittest/test/unittest_runtests_without_tests_test.dart b/pkg/unittest/test/unittest_runtests_without_tests_test.dart
new file mode 100644
index 0000000..e8c26f8
--- /dev/null
+++ b/pkg/unittest/test/unittest_runtests_without_tests_test.dart
@@ -0,0 +1,18 @@
+// Copyright (c) 2013, 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 unittestTest;
+import 'dart:isolate';
+import 'dart:async';
+import 'package:unittest/unittest.dart';
+
+part 'unittest_test_utils.dart';
+
+var testName = 'runTests() without tests';
+
+var testFunction = (_) {
+ runTests();
+};
+
+var expected = buildStatusString(0, 0, 0, null);
diff --git a/pkg/unittest/test/unittest_setup_and_teardown_test.dart b/pkg/unittest/test/unittest_setup_and_teardown_test.dart
new file mode 100644
index 0000000..0c20cf3
--- /dev/null
+++ b/pkg/unittest/test/unittest_setup_and_teardown_test.dart
@@ -0,0 +1,23 @@
+// Copyright (c) 2013, 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 unittestTest;
+import 'dart:isolate';
+import 'dart:async';
+import 'package:unittest/unittest.dart';
+
+part 'unittest_test_utils.dart';
+
+var testName = 'setup and teardown test';
+
+var testFunction = (TestConfiguration testConfig) {
+ group('a', () {
+ setUp(() { testConfig.setup = 'setup'; });
+ tearDown(() { testConfig.teardown = 'teardown'; });
+ test(testName, () {});
+ });
+};
+
+var expected = buildStatusString(1, 0, 0, 'a $testName', count: 0,
+ setup: 'setup', teardown: 'teardown');
diff --git a/pkg/unittest/test/unittest_setup_test.dart b/pkg/unittest/test/unittest_setup_test.dart
new file mode 100644
index 0000000..0050f64
--- /dev/null
+++ b/pkg/unittest/test/unittest_setup_test.dart
@@ -0,0 +1,24 @@
+// Copyright (c) 2013, 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 unittestTest;
+import 'dart:isolate';
+import 'dart:async';
+import 'package:unittest/unittest.dart';
+
+part 'unittest_test_utils.dart';
+
+var testName = 'setup test';
+
+var testFunction = (TestConfiguration testConfig) {
+ group('a', () {
+ setUp(() { testConfig.setup = 'setup'; });
+ test(testName, () {});
+ });
+};
+
+var expected = buildStatusString(1, 0, 0, 'a $testName',
+ count: 0, setup: 'setup');
+
+
diff --git a/pkg/unittest/test/unittest_single_correct_test.dart b/pkg/unittest/test/unittest_single_correct_test.dart
new file mode 100644
index 0000000..23c31fd
--- /dev/null
+++ b/pkg/unittest/test/unittest_single_correct_test.dart
@@ -0,0 +1,18 @@
+// Copyright (c) 2013, 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 unittestTest;
+import 'dart:isolate';
+import 'dart:async';
+import 'package:unittest/unittest.dart';
+
+part 'unittest_test_utils.dart';
+
+var testName = 'single correct test';
+
+var testFunction = (_) {
+ test(testName, () => expect(2 + 3, equals(5)));
+};
+
+var expected = buildStatusString(1, 0, 0, testName);
diff --git a/pkg/unittest/test/unittest_single_failing_test.dart b/pkg/unittest/test/unittest_single_failing_test.dart
new file mode 100644
index 0000000..c965e7a
--- /dev/null
+++ b/pkg/unittest/test/unittest_single_failing_test.dart
@@ -0,0 +1,19 @@
+// Copyright (c) 2013, 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 unittestTest;
+import 'dart:isolate';
+import 'dart:async';
+import 'package:unittest/unittest.dart';
+
+part 'unittest_test_utils.dart';
+
+var testName = 'single failing test';
+
+var testFunction = (_) {
+ test(testName, () => expect(2 + 2, equals(5)));
+};
+
+var expected = buildStatusString(0, 1, 0, testName,
+ message: 'Expected: <5> Actual: <4>');
diff --git a/pkg/unittest/test/unittest_skipped_soloed_nested_test.dart b/pkg/unittest/test/unittest_skipped_soloed_nested_test.dart
new file mode 100644
index 0000000..2ec908d
--- /dev/null
+++ b/pkg/unittest/test/unittest_skipped_soloed_nested_test.dart
@@ -0,0 +1,77 @@
+// Copyright (c) 2013, 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 unittestTest;
+import 'dart:isolate';
+import 'dart:async';
+import 'package:unittest/unittest.dart';
+
+part 'unittest_test_utils.dart';
+
+var testName = 'skipped/soloed nested groups with setup/teardown';
+
+var testFunction = (_) {
+ StringBuffer s = null;
+ setUp(() {
+ if (s == null)
+ s = new StringBuffer();
+ });
+ test('top level', () {
+ s.write('A');
+ });
+ skip_test('skipped top level', () {
+ s.write('B');
+ });
+ skip_group('skipped top level group', () {
+ setUp(() {
+ s.write('C');
+ });
+ solo_test('skipped solo nested test', () {
+ s.write('D');
+ });
+ });
+ group('non-solo group', () {
+ setUp(() {
+ s.write('E');
+ });
+ test('in non-solo group', () {
+ s.write('F');
+ });
+ solo_test('solo_test in non-solo group', () {
+ s.write('G');
+ });
+ });
+ solo_group('solo group', () {
+ setUp(() {
+ s.write('H');
+ });
+ test('solo group non-solo test', () {
+ s.write('I');
+ });
+ solo_test('solo group solo test', () {
+ s.write('J');
+ });
+ group('nested non-solo group in solo group', () {
+ test('nested non-solo group non-solo test', () {
+ s.write('K');
+ });
+ solo_test('nested non-solo group solo test', () {
+ s.write('L');
+ });
+ });
+ });
+ solo_test('final', () {
+ expect(s.toString(), "EGHIHJHKHL");
+ });
+};
+
+var expected = buildStatusString(6, 0, 0,
+ 'non-solo group solo_test in non-solo group::'
+ 'solo group solo group non-solo test::'
+ 'solo group solo group solo test::'
+ 'solo group nested non-solo group in solo group nested non-'
+ 'solo group non-solo test::'
+ 'solo group nested non-solo group in solo'
+ ' group nested non-solo group solo test::'
+ 'final');
diff --git a/pkg/unittest/test/unittest_teardown_test.dart b/pkg/unittest/test/unittest_teardown_test.dart
new file mode 100644
index 0000000..c01bdaf
--- /dev/null
+++ b/pkg/unittest/test/unittest_teardown_test.dart
@@ -0,0 +1,22 @@
+// Copyright (c) 2013, 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 unittestTest;
+import 'dart:isolate';
+import 'dart:async';
+import 'package:unittest/unittest.dart';
+
+part 'unittest_test_utils.dart';
+
+var testName = 'teardown test';
+
+var testFunction = (TestConfiguration testConfig) {
+ group('a', () {
+ tearDown(() { testConfig.teardown = 'teardown'; });
+ test(testName, () {});
+ });
+};
+
+var expected = buildStatusString(1, 0, 0, 'a $testName',
+ count: 0, setup: '', teardown: 'teardown');
diff --git a/pkg/unittest/test/unittest_test.dart b/pkg/unittest/test/unittest_test.dart
deleted file mode 100644
index 852ea73..0000000
--- a/pkg/unittest/test/unittest_test.dart
+++ /dev/null
@@ -1,479 +0,0 @@
-// Copyright (c) 2012, 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.
-
-// TODO(gram):
-// Unfortunately I can't seem to test anything that involves timeouts, e.g.
-// insufficient callbacks, because the timeout is controlled externally
-// (test.dart?), and we would need to use a shorter timeout for the inner tests
-// so the outer timeout doesn't fire. So I removed all such tests.
-// I'd like to revisit this at some point.
-
-library unittestTest;
-import 'dart:isolate';
-import 'dart:async';
-import 'package:unittest/unittest.dart';
-
-Future _defer(void fn()) {
- return new Future.sync(fn);
-}
-
-String buildStatusString(int passed, int failed, int errors,
- var results,
- {int count: 0,
- String setup: '', String teardown: '',
- String uncaughtError: null,
- String message: ''}) {
- var totalTests = 0;
- var testDetails = new StringBuffer();
- if(results == null) {
- // no op
- assert(message == '');
- } else if (results is String) {
- totalTests = passed + failed + errors;
- testDetails.write(':$results:$message');
- } else {
- totalTests = results.length;
- for (var i = 0; i < results.length; i++) {
- testDetails.write(':${results[i].description}:'
- '${collapseWhitespace(results[i].message)}');
- }
- }
- return '$passed:$failed:$errors:$totalTests:$count:'
- '$setup:$teardown:$uncaughtError$testDetails';
-}
-
-class TestConfiguration extends Configuration {
-
- // Some test state that is captured
- int count = 0; // a count of callbacks
- String setup = ''; // the name of the test group setup function, if any
- String teardown = ''; // the name of the test group teardown function, if any
-
- // The port to communicate with the parent isolate
- final SendPort _port;
- String _result;
-
- TestConfiguration(this._port);
-
- void onSummary(int passed, int failed, int errors, List<TestCase> results,
- String uncaughtError) {
- _result = buildStatusString(passed, failed, errors, results,
- count: count, setup: setup, teardown: teardown,
- uncaughtError: uncaughtError);
- }
-
- void onDone(bool success) {
- _port.send(_result);
- }
-}
-
-makeDelayedSetup(index, s) => () {
- return new Future.delayed(new Duration(milliseconds:1), () {
- s.write('l$index U ');
- });
-};
-
-makeDelayedTeardown(index, s) => () {
- return new Future.delayed(new Duration(milliseconds:1), () {
- s.write('l$index D ');
- });
-};
-
-makeImmediateSetup(index, s) => () {
- s.write('l$index U ');
-};
-
-makeImmediateTeardown(index, s) => () {
- s.write('l$index D ');
-};
-
-runTest() {
- port.receive((String testName, sendport) {
- var testConfig = new TestConfiguration(sendport);
- unittestConfiguration = testConfig;
-
- if (testName == 'single correct test') {
- test(testName, () => expect(2 + 3, equals(5)));
- } else if (testName == 'single failing test') {
- test(testName, () => expect(2 + 2, equals(5)));
- } else if (testName == 'exception test') {
- test(testName, () { throw new Exception('Fail.'); });
- } else if (testName == 'group name test') {
- group('a', () {
- test('a', () {});
- group('b', () {
- test('b', () {});
- });
- });
- } else if (testName == 'setup test') {
- group('a', () {
- setUp(() { testConfig.setup = 'setup'; });
- test(testName, () {});
- });
- } else if (testName == 'teardown test') {
- group('a', () {
- tearDown(() { testConfig.teardown = 'teardown'; });
- test(testName, () {});
- });
- } else if (testName == 'setup and teardown test') {
- group('a', () {
- setUp(() { testConfig.setup = 'setup'; });
- tearDown(() { testConfig.teardown = 'teardown'; });
- test(testName, () {});
- });
- } else if (testName == 'correct callback test') {
- test(testName,
- () =>_defer(expectAsync0((){ ++testConfig.count;})));
- } else if (testName == 'excess callback test') {
- test(testName, () {
- var _callback0 = expectAsync0(() => ++testConfig.count);
- var _callback1 = expectAsync0(() => ++testConfig.count);
- var _callback2 = expectAsync0(() {
- _callback1();
- _callback1();
- _callback0();
- });
- _defer(_callback2);
- });
- } else if (testName == 'completion test') {
- test(testName, () {
- var _callback;
- _callback = expectAsyncUntil0(() {
- if (++testConfig.count < 10) {
- _defer(_callback);
- }
- },
- () => (testConfig.count == 10));
- _defer(_callback);
- });
- } else if (testName == 'async exception test') {
- test(testName, () {
- expectAsync0(() {});
- _defer(() => guardAsync(() { throw "error!"; }));
- });
- } else if (testName == 'late exception test') {
- var f;
- test('testOne', () {
- f = expectAsync0(() {});
- _defer(f);
- });
- test('testTwo', () {
- _defer(expectAsync0(() { f(); }));
- });
- } else if (testName == 'middle exception test') {
- test('testOne', () { expect(true, isTrue); });
- test('testTwo', () { expect(true, isFalse); });
- test('testThree', () {
- var done = expectAsync0((){});
- _defer(() {
- expect(true, isTrue);
- done();
- });
- });
- } else if (testName == 'async setup/teardown test') {
- group('good setup/good teardown', () {
- setUp(() {
- return new Future.value(0);
- });
- tearDown(() {
- return new Future.value(0);
- });
- test('foo1', (){});
- });
- group('good setup/bad teardown', () {
- setUp(() {
- return new Future.value(0);
- });
- tearDown(() {
- return new Future.error("Failed to complete tearDown");
- });
- test('foo2', (){});
- });
- group('bad setup/good teardown', () {
- setUp(() {
- return new Future.error("Failed to complete setUp");
- });
- tearDown(() {
- return new Future.value(0);
- });
- test('foo3', (){});
- });
- group('bad setup/bad teardown', () {
- setUp(() {
- return new Future.error("Failed to complete setUp");
- });
- tearDown(() {
- return new Future.error("Failed to complete tearDown");
- });
- test('foo4', (){});
- });
- // The next test is just to make sure we make steady progress
- // through the tests.
- test('post groups', () {});
- } else if (testName == 'test returning future') {
- test("successful", () {
- return _defer(() {
- expect(true, true);
- });
- });
- // We repeat the fail and error tests, because during development
- // I had a situation where either worked fine on their own, and
- // error/fail worked, but fail/error would time out.
- test("error1", () {
- var callback = expectAsync0((){});
- var excesscallback = expectAsync0((){});
- return _defer(() {
- excesscallback();
- excesscallback();
- excesscallback();
- callback();
- });
- });
- test("fail1", () {
- return _defer(() {
- expect(true, false);
- });
- });
- test("error2", () {
- var callback = expectAsync0((){});
- var excesscallback = expectAsync0((){});
- return _defer(() {
- excesscallback();
- excesscallback();
- callback();
- });
- });
- test("fail2", () {
- return _defer(() {
- fail('failure');
- });
- });
- test('foo5', () {
- });
- } else if (testName == 'test returning future using runAsync') {
- test("successful", () {
- return _defer(() {
- runAsync(() {
- guardAsync(() {
- expect(true, true);
- });
- });
- });
- });
- test("fail1", () {
- var callback = expectAsync0((){});
- return _defer(() {
- runAsync(() {
- guardAsync(() {
- expect(true, false);
- callback();
- });
- });
- });
- });
- test('error1', () {
- var callback = expectAsync0((){});
- var excesscallback = expectAsync0((){});
- return _defer(() {
- runAsync(() {
- guardAsync(() {
- excesscallback();
- excesscallback();
- callback();
- });
- });
- });
- });
- test("fail2", () {
- var callback = expectAsync0((){});
- return _defer(() {
- runAsync(() {
- guardAsync(() {
- fail('failure');
- callback();
- });
- });
- });
- });
- test('error2', () {
- var callback = expectAsync0((){});
- var excesscallback = expectAsync0((){});
- return _defer(() {
- runAsync(() {
- guardAsync(() {
- excesscallback();
- excesscallback();
- excesscallback();
- callback();
- });
- });
- });
- });
- test('foo6', () {
- });
- } else if (testName == 'testCases immutable') {
- test(testName, () {
- expect(() => testCases.clear(), throwsUnsupportedError);
- expect(() => testCases.removeLast(), throwsUnsupportedError);
- });
- } else if (testName == 'runTests without tests') {
- runTests();
- } else if (testName == 'nested groups setup/teardown') {
- StringBuffer s = new StringBuffer();
- group('level 1', () {
- setUp(makeDelayedSetup(1, s));
- group('level 2', () {
- setUp(makeImmediateSetup(2, s));
- tearDown(makeDelayedTeardown(2, s));
- group('level 3', () {
- group('level 4', () {
- setUp(makeDelayedSetup(4, s));
- tearDown(makeImmediateTeardown(4, s));
- group('level 5', () {
- setUp(makeImmediateSetup(5, s));
- group('level 6', () {
- tearDown(makeDelayedTeardown(6, s));
- test('inner', () {});
- });
- });
- });
- });
- });
- });
- test('after nest', () {
- expect(s.toString(), "l1 U l2 U l4 U l5 U l6 D l4 D l2 D ");
- });
- } else if (testName == 'skipped/soloed nested groups with setup/teardown') {
- StringBuffer s = null;
- setUp(() {
- if (s == null)
- s = new StringBuffer();
- });
- test('top level', () {
- s.write('A');
- });
- skip_test('skipped top level', () {
- s.write('B');
- });
- skip_group('skipped top level group', () {
- setUp(() {
- s.write('C');
- });
- solo_test('skipped solo nested test', () {
- s.write('D');
- });
- });
- group('non-solo group', () {
- setUp(() {
- s.write('E');
- });
- test('in non-solo group', () {
- s.write('F');
- });
- solo_test('solo_test in non-solo group', () {
- s.write('G');
- });
- });
- solo_group('solo group', () {
- setUp(() {
- s.write('H');
- });
- test('solo group non-solo test', () {
- s.write('I');
- });
- solo_test('solo group solo test', () {
- s.write('J');
- });
- group('nested non-solo group in solo group', () {
- test('nested non-solo group non-solo test', () {
- s.write('K');
- });
- solo_test('nested non-solo group solo test', () {
- s.write('L');
- });
- });
- });
- solo_test('final', () {
- expect(s.toString(), "EGHIHJHKHL");
- });
- }
- });
-}
-
-main() {
- var tests = {
- 'single correct test': buildStatusString(1, 0, 0, 'single correct test'),
- 'single failing test': buildStatusString(0, 1, 0, 'single failing test',
- message: 'Expected: <5> Actual: <4>'),
- 'exception test': buildStatusString(0, 0, 1, 'exception test',
- message: 'Test failed: Caught Exception: Fail.'),
- 'group name test': buildStatusString(2, 0, 0, 'a a::a b b'),
- 'setup test': buildStatusString(1, 0, 0, 'a setup test',
- count: 0, setup: 'setup'),
- 'teardown test': buildStatusString(1, 0, 0, 'a teardown test',
- count: 0, setup: '', teardown: 'teardown'),
- 'setup and teardown test': buildStatusString(1, 0, 0,
- 'a setup and teardown test', count: 0, setup: 'setup',
- teardown: 'teardown'),
- 'correct callback test': buildStatusString(1, 0, 0, 'correct callback test',
- count: 1),
- 'excess callback test': buildStatusString(0, 1, 0, 'excess callback test',
- count: 1, message: 'Callback called more times than expected (1).'),
- 'completion test': buildStatusString(1, 0, 0, 'completion test', count: 10),
- 'async exception test': buildStatusString(0, 1, 0, 'async exception test',
- message: 'Caught error!'),
- 'late exception test': buildStatusString(1, 0, 1, 'testOne',
- message: 'Callback called (2) after test case testOne has already '
- 'been marked as pass.:testTwo:'),
- 'middle exception test': buildStatusString(2, 1, 0,
- 'testOne::testTwo:Expected: false Actual: <true>:testThree'),
- 'async setup/teardown test': buildStatusString(2, 0, 3,
- 'good setup/good teardown foo1::'
- 'good setup/bad teardown foo2:'
- 'Teardown failed: Caught Failed to complete tearDown:'
- 'bad setup/good teardown foo3:'
- 'Setup failed: Caught Failed to complete setUp:'
- 'bad setup/bad teardown foo4:'
- 'Setup failed: Caught Failed to complete setUp:'
- 'post groups'),
- 'test returning future': buildStatusString(2, 4, 0,
- 'successful::'
- 'error1:Callback called more times than expected (1).:'
- 'fail1:Expected: <false> Actual: <true>:'
- 'error2:Callback called more times than expected (1).:'
- 'fail2:failure:'
- 'foo5'),
- 'test returning future using runAsync': buildStatusString(2, 4, 0,
- 'successful::'
- 'fail1:Expected: <false> Actual: <true>:'
- 'error1:Callback called more times than expected (1).:'
- 'fail2:failure:'
- 'error2:Callback called more times than expected (1).:'
- 'foo6'),
- 'testCases immutable':
- buildStatusString(1, 0, 0, 'testCases immutable'),
- 'runTests without tests': buildStatusString(0, 0, 0, null),
- 'nested groups setup/teardown':
- buildStatusString(2, 0, 0,
- 'level 1 level 2 level 3 level 4 level 5 level 6 inner::'
- 'after nest'),
- 'skipped/soloed nested groups with setup/teardown':
- buildStatusString(6, 0, 0,
- 'non-solo group solo_test in non-solo group::'
- 'solo group solo group non-solo test::'
- 'solo group solo group solo test::'
- 'solo group nested non-solo group in solo group nested non-'
- 'solo group non-solo test::'
- 'solo group nested non-solo group in solo'
- ' group nested non-solo group solo test::'
- 'final')
- };
-
- tests.forEach((String name, String expected) {
- test(name, () => spawnFunction(runTest)
- .call(name)
- .then((String msg) => expect(msg.trim(), equals(expected))));
- });
-}
-
diff --git a/pkg/unittest/test/unittest_test_returning_future_test.dart b/pkg/unittest/test/unittest_test_returning_future_test.dart
new file mode 100644
index 0000000..a74a8db
--- /dev/null
+++ b/pkg/unittest/test/unittest_test_returning_future_test.dart
@@ -0,0 +1,62 @@
+// Copyright (c) 2013, 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 unittestTest;
+import 'dart:isolate';
+import 'dart:async';
+import 'package:unittest/unittest.dart';
+
+part 'unittest_test_utils.dart';
+
+var testName = 'test returning future';
+
+var testFunction = (_) {
+ test("successful", () {
+ return _defer(() {
+ expect(true, true);
+ });
+ });
+ // We repeat the fail and error tests, because during development
+ // I had a situation where either worked fine on their own, and
+ // error/fail worked, but fail/error would time out.
+ test("error1", () {
+ var callback = expectAsync0((){});
+ var excesscallback = expectAsync0((){});
+ return _defer(() {
+ excesscallback();
+ excesscallback();
+ excesscallback();
+ callback();
+ });
+ });
+ test("fail1", () {
+ return _defer(() {
+ expect(true, false);
+ });
+ });
+ test("error2", () {
+ var callback = expectAsync0((){});
+ var excesscallback = expectAsync0((){});
+ return _defer(() {
+ excesscallback();
+ excesscallback();
+ callback();
+ });
+ });
+ test("fail2", () {
+ return _defer(() {
+ fail('failure');
+ });
+ });
+ test('foo5', () {
+ });
+};
+
+var expected = buildStatusString(2, 4, 0,
+ 'successful::'
+ 'error1:Callback called more times than expected (1).:'
+ 'fail1:Expected: <false> Actual: <true>:'
+ 'error2:Callback called more times than expected (1).:'
+ 'fail2:failure:'
+ 'foo5');
diff --git a/pkg/unittest/test/unittest_test_returning_future_using_runasync_test.dart b/pkg/unittest/test/unittest_test_returning_future_using_runasync_test.dart
new file mode 100644
index 0000000..2b8d343
--- /dev/null
+++ b/pkg/unittest/test/unittest_test_returning_future_using_runasync_test.dart
@@ -0,0 +1,83 @@
+// Copyright (c) 2013, 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 unittestTest;
+import 'dart:isolate';
+import 'dart:async';
+import 'package:unittest/unittest.dart';
+
+part 'unittest_test_utils.dart';
+
+var testName = 'test returning future using runAsync';
+
+var testFunction = (_) {
+ test("successful", () {
+ return _defer(() {
+ runAsync(() {
+ guardAsync(() {
+ expect(true, true);
+ });
+ });
+ });
+ });
+ test("fail1", () {
+ var callback = expectAsync0((){});
+ return _defer(() {
+ runAsync(() {
+ guardAsync(() {
+ expect(true, false);
+ callback();
+ });
+ });
+ });
+ });
+ test('error1', () {
+ var callback = expectAsync0((){});
+ var excesscallback = expectAsync0((){});
+ return _defer(() {
+ runAsync(() {
+ guardAsync(() {
+ excesscallback();
+ excesscallback();
+ callback();
+ });
+ });
+ });
+ });
+ test("fail2", () {
+ var callback = expectAsync0((){});
+ return _defer(() {
+ runAsync(() {
+ guardAsync(() {
+ fail('failure');
+ callback();
+ });
+ });
+ });
+ });
+ test('error2', () {
+ var callback = expectAsync0((){});
+ var excesscallback = expectAsync0((){});
+ return _defer(() {
+ runAsync(() {
+ guardAsync(() {
+ excesscallback();
+ excesscallback();
+ excesscallback();
+ callback();
+ });
+ });
+ });
+ });
+ test('foo6', () {
+ });
+};
+
+var expected = buildStatusString(2, 4, 0,
+ 'successful::'
+ 'fail1:Expected: <false> Actual: <true>:'
+ 'error1:Callback called more times than expected (1).:'
+ 'fail2:failure:'
+ 'error2:Callback called more times than expected (1).:'
+ 'foo6');
diff --git a/pkg/unittest/test/unittest_test_utils.dart b/pkg/unittest/test/unittest_test_utils.dart
new file mode 100644
index 0000000..ab83927
--- /dev/null
+++ b/pkg/unittest/test/unittest_test_utils.dart
@@ -0,0 +1,95 @@
+// Copyright (c) 2013, 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 unittestTest;
+
+Future _defer(void fn()) {
+ return new Future.sync(fn);
+}
+
+String buildStatusString(int passed, int failed, int errors,
+ var results,
+ {int count: 0,
+ String setup: '', String teardown: '',
+ String uncaughtError: null,
+ String message: ''}) {
+ var totalTests = 0;
+ var testDetails = new StringBuffer();
+ if(results == null) {
+ // no op
+ assert(message == '');
+ } else if (results is String) {
+ totalTests = passed + failed + errors;
+ testDetails.write(':$results:$message');
+ } else {
+ totalTests = results.length;
+ for (var i = 0; i < results.length; i++) {
+ testDetails.write(':${results[i].description}:'
+ '${collapseWhitespace(results[i].message)}');
+ }
+ }
+ return '$passed:$failed:$errors:$totalTests:$count:'
+ '$setup:$teardown:$uncaughtError$testDetails';
+}
+
+class TestConfiguration extends Configuration {
+
+ // Some test state that is captured.
+ int count = 0; // A count of callbacks.
+ String setup = ''; // The name of the test group setup function, if any.
+ String teardown = ''; // The name of the group teardown function, if any.
+
+ // The port to communicate with the parent isolate
+ final SendPort _port;
+ String _result;
+
+ TestConfiguration(this._port);
+
+ void onSummary(int passed, int failed, int errors, List<TestCase> results,
+ String uncaughtError) {
+ _result = buildStatusString(passed, failed, errors, results,
+ count: count, setup: setup, teardown: teardown,
+ uncaughtError: uncaughtError);
+ }
+
+ void onDone(bool success) {
+ _port.send(_result);
+ }
+}
+
+makeDelayedSetup(index, s) => () {
+ return new Future.delayed(new Duration(milliseconds:1), () {
+ s.write('l$index U ');
+ });
+};
+
+makeDelayedTeardown(index, s) => () {
+ return new Future.delayed(new Duration(milliseconds:1), () {
+ s.write('l$index D ');
+ });
+};
+
+makeImmediateSetup(index, s) => () {
+ s.write('l$index U ');
+};
+
+makeImmediateTeardown(index, s) => () {
+ s.write('l$index D ');
+};
+
+runTestInIsolate() {
+ port.receive((_, sendport) {
+ var testConfig = new TestConfiguration(sendport);
+ unittestConfiguration = testConfig;
+ testFunction(testConfig);
+ });
+}
+
+main() {
+ spawnFunction(runTestInIsolate)
+ .call('')
+ .then((String msg) {
+ expect(msg.trim(), equals(expected));
+ });
+}
diff --git a/pkg/unittest/test/unittest_testcases_immutable_test.dart b/pkg/unittest/test/unittest_testcases_immutable_test.dart
new file mode 100644
index 0000000..891ea3a
--- /dev/null
+++ b/pkg/unittest/test/unittest_testcases_immutable_test.dart
@@ -0,0 +1,21 @@
+// Copyright (c) 2013, 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 unittestTest;
+import 'dart:isolate';
+import 'dart:async';
+import 'package:unittest/unittest.dart';
+
+part 'unittest_test_utils.dart';
+
+var testName = 'testcases immutable';
+
+var testFunction = (_) {
+ test(testName, () {
+ expect(() => testCases.clear(), throwsUnsupportedError);
+ expect(() => testCases.removeLast(), throwsUnsupportedError);
+ });
+};
+
+var expected = buildStatusString(1, 0, 0, testName);
diff --git a/pkg/unittest/test/unitttest_group_name_test.dart b/pkg/unittest/test/unitttest_group_name_test.dart
new file mode 100644
index 0000000..8f6b87b
--- /dev/null
+++ b/pkg/unittest/test/unitttest_group_name_test.dart
@@ -0,0 +1,23 @@
+// Copyright (c) 2013, 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 unittestTest;
+import 'dart:isolate';
+import 'dart:async';
+import 'package:unittest/unittest.dart';
+
+part 'unittest_test_utils.dart';
+
+var testName = 'group name test';
+
+var testFunction = (_) {
+ group('a', () {
+ test('a', () {});
+ group('b', () {
+ test('b', () {});
+ });
+ });
+};
+
+var expected = buildStatusString(2, 0, 0, 'a a::a b b');
diff --git a/runtime/bin/dartutils.cc b/runtime/bin/dartutils.cc
index 5de42ac..a90694d 100644
--- a/runtime/bin/dartutils.cc
+++ b/runtime/bin/dartutils.cc
@@ -389,6 +389,7 @@
return Dart_Error(error_msg);
}
Dart_Handle str = Dart_NewStringFromUTF8(text_buffer, len);
+ free(const_cast<uint8_t *>(text_buffer));
return str;
}
@@ -594,23 +595,27 @@
Dart_StringToCString(script_path, &script_path_cstr);
const char* error_msg = NULL;
intptr_t len;
- const uint8_t* text_buffer = ReadFileFully(script_path_cstr,
- &len,
- &error_msg);
- if (text_buffer == NULL) {
+ const uint8_t* buffer = ReadFileFully(script_path_cstr,
+ &len,
+ &error_msg);
+ if (buffer == NULL) {
return Dart_Error(error_msg);
}
bool is_snapshot = false;
- text_buffer = SniffForMagicNumber(text_buffer, &len, &is_snapshot);
+ const uint8_t *payload = SniffForMagicNumber(buffer, &len, &is_snapshot);
+ Dart_Handle returnValue;
if (is_snapshot) {
- return Dart_LoadScriptFromSnapshot(text_buffer, len);
+ returnValue = Dart_LoadScriptFromSnapshot(payload, len);
} else {
- Dart_Handle source = Dart_NewStringFromUTF8(text_buffer, len);
+ Dart_Handle source = Dart_NewStringFromUTF8(buffer, len);
if (Dart_IsError(source)) {
- return source;
+ returnValue = source;
+ } else {
+ returnValue = Dart_LoadScript(resolved_script_uri, source, 0, 0);
}
- return Dart_LoadScript(resolved_script_uri, source, 0, 0);
}
+ free(const_cast<uint8_t *>(buffer));
+ return returnValue;
}
diff --git a/runtime/bin/io_natives.cc b/runtime/bin/io_natives.cc
index f9adf09..e771d89 100644
--- a/runtime/bin/io_natives.cc
+++ b/runtime/bin/io_natives.cc
@@ -50,6 +50,7 @@
V(SecureSocket_RegisterHandshakeCompleteCallback, 2) \
V(SecureSocket_Renegotiate, 4) \
V(SecureSocket_InitializeLibrary, 3) \
+ V(SecureSocket_AddCertificate, 2) \
V(SecureSocket_NewServicePort, 0) \
V(SecureSocket_FilterPointer, 1) \
V(ServerSocket_CreateBindListen, 5) \
diff --git a/runtime/bin/secure_socket.cc b/runtime/bin/secure_socket.cc
index 9cf0d7d..ad6ae82 100644
--- a/runtime/bin/secure_socket.cc
+++ b/runtime/bin/secure_socket.cc
@@ -278,6 +278,92 @@
}
+static Dart_Handle X509FromCertificate(CERTCertificate* certificate) {
+ PRTime start_validity;
+ PRTime end_validity;
+ SECStatus status =
+ CERT_GetCertTimes(certificate, &start_validity, &end_validity);
+ if (status != SECSuccess) {
+ ThrowPRException("CertificateException",
+ "Cannot get validity times from certificate");
+ }
+ int64_t start_epoch_ms = start_validity / PR_USEC_PER_MSEC;
+ int64_t end_epoch_ms = end_validity / PR_USEC_PER_MSEC;
+ Dart_Handle subject_name_object =
+ DartUtils::NewString(certificate->subjectName);
+ Dart_Handle issuer_name_object =
+ DartUtils::NewString(certificate->issuerName);
+ Dart_Handle start_epoch_ms_int = Dart_NewInteger(start_epoch_ms);
+ Dart_Handle end_epoch_ms_int = Dart_NewInteger(end_epoch_ms);
+
+ Dart_Handle date_type =
+ DartUtils::GetDartType(DartUtils::kCoreLibURL, "DateTime");
+ Dart_Handle from_milliseconds =
+ DartUtils::NewString("fromMillisecondsSinceEpoch");
+
+ Dart_Handle start_validity_date =
+ Dart_New(date_type, from_milliseconds, 1, &start_epoch_ms_int);
+ Dart_Handle end_validity_date =
+ Dart_New(date_type, from_milliseconds, 1, &end_epoch_ms_int);
+
+ Dart_Handle x509_type =
+ DartUtils::GetDartType(DartUtils::kIOLibURL, "X509Certificate");
+ Dart_Handle arguments[] = { subject_name_object,
+ issuer_name_object,
+ start_validity_date,
+ end_validity_date };
+ return Dart_New(x509_type, Dart_Null(), 4, arguments);
+}
+
+
+void FUNCTION_NAME(SecureSocket_AddCertificate)
+ (Dart_NativeArguments args) {
+ Dart_EnterScope();
+ Dart_Handle certificate_object =
+ ThrowIfError(Dart_GetNativeArgument(args, 0));
+ Dart_Handle trust_object = ThrowIfError(Dart_GetNativeArgument(args, 1));
+
+ if (!Dart_IsList(certificate_object) || !Dart_IsString(trust_object)) {
+ Dart_ThrowException(DartUtils::NewDartArgumentError(
+ "Bad argument to SecureSocket.addCertificate"));
+ }
+
+ intptr_t length;
+ ThrowIfError(Dart_ListLength(certificate_object, &length));
+ uint8_t* certificate = reinterpret_cast<uint8_t*>(malloc(length + 1));
+ if (certificate == NULL) {
+ FATAL("Out of memory in SecureSocket.addCertificate");
+ }
+ ThrowIfError(Dart_ListGetAsBytes(
+ certificate_object, 0, certificate, length));
+
+ const char* trust_string;
+ ThrowIfError(Dart_StringToCString(trust_object,
+ &trust_string));
+
+ CERTCertificate* cert = CERT_DecodeCertFromPackage(
+ reinterpret_cast<char*>(certificate), length);
+ if (cert == NULL) {
+ ThrowPRException("CertificateException", "Certificate cannot be decoded");
+ }
+ CERTCertTrust trust;
+ SECStatus status = CERT_DecodeTrustString(&trust, trust_string);
+ if (status != SECSuccess) {
+ ThrowPRException("CertificateException", "Trust string cannot be decoded");
+ }
+
+ status = CERT_ChangeCertTrust(CERT_GetDefaultCertDB(), cert, &trust);
+ if (status != SECSuccess) {
+ ThrowPRException("CertificateException", "Cannot set trust attributes");
+ }
+
+ Dart_SetReturnValue(args, X509FromCertificate(cert));
+ Dart_ExitScope();
+ return;
+}
+
+
+
void FUNCTION_NAME(SecureSocket_PeerCertificate)
(Dart_NativeArguments args) {
Dart_EnterScope();
@@ -428,44 +514,6 @@
}
-static Dart_Handle X509FromCertificate(CERTCertificate* certificate) {
- PRTime start_validity;
- PRTime end_validity;
- SECStatus status =
- CERT_GetCertTimes(certificate, &start_validity, &end_validity);
- if (status != SECSuccess) {
- ThrowPRException("CertificateException",
- "Cannot get validity times from certificate");
- }
- int64_t start_epoch_ms = start_validity / PR_USEC_PER_MSEC;
- int64_t end_epoch_ms = end_validity / PR_USEC_PER_MSEC;
- Dart_Handle subject_name_object =
- DartUtils::NewString(certificate->subjectName);
- Dart_Handle issuer_name_object =
- DartUtils::NewString(certificate->issuerName);
- Dart_Handle start_epoch_ms_int = Dart_NewInteger(start_epoch_ms);
- Dart_Handle end_epoch_ms_int = Dart_NewInteger(end_epoch_ms);
-
- Dart_Handle date_type =
- DartUtils::GetDartType(DartUtils::kCoreLibURL, "DateTime");
- Dart_Handle from_milliseconds =
- DartUtils::NewString("fromMillisecondsSinceEpoch");
-
- Dart_Handle start_validity_date =
- Dart_New(date_type, from_milliseconds, 1, &start_epoch_ms_int);
- Dart_Handle end_validity_date =
- Dart_New(date_type, from_milliseconds, 1, &end_epoch_ms_int);
-
- Dart_Handle x509_type =
- DartUtils::GetDartType(DartUtils::kIOLibURL, "X509Certificate");
- Dart_Handle arguments[] = { subject_name_object,
- issuer_name_object,
- start_validity_date,
- end_validity_date };
- return Dart_New(x509_type, Dart_Null(), 4, arguments);
-}
-
-
void SSLFilter::Init(Dart_Handle dart_this) {
if (!library_initialized_) {
InitializeLibrary(NULL, "", true, false);
diff --git a/runtime/bin/secure_socket_patch.dart b/runtime/bin/secure_socket_patch.dart
index 104f562..96d6565a 100644
--- a/runtime/bin/secure_socket_patch.dart
+++ b/runtime/bin/secure_socket_patch.dart
@@ -9,7 +9,11 @@
/* patch */ static void initialize({String database,
String password,
bool useBuiltinRoots: true})
- native "SecureSocket_InitializeLibrary";
+ native "SecureSocket_InitializeLibrary";
+
+ /* patch */ static X509Certificate addCertificate(List<int> certificate,
+ String trust)
+ native "SecureSocket_AddCertificate";
}
diff --git a/runtime/bin/secure_socket_unsupported.cc b/runtime/bin/secure_socket_unsupported.cc
index de97dc8..6695fa9 100644
--- a/runtime/bin/secure_socket_unsupported.cc
+++ b/runtime/bin/secure_socket_unsupported.cc
@@ -27,6 +27,14 @@
}
+void FUNCTION_NAME(SecureSocket_AddCertificate)(Dart_NativeArguments args) {
+ Dart_EnterScope();
+ Dart_ThrowException(DartUtils::NewDartArgumentError(
+ "Secure Sockets unsupported on this platform"));
+ Dart_ExitScope();
+}
+
+
void FUNCTION_NAME(SecureSocket_Destroy)(Dart_NativeArguments args) {
Dart_EnterScope();
Dart_ThrowException(DartUtils::NewDartArgumentError(
diff --git a/runtime/include/dart_api.h b/runtime/include/dart_api.h
index e336288..b47b40c 100755
--- a/runtime/include/dart_api.h
+++ b/runtime/include/dart_api.h
@@ -1981,6 +1981,15 @@
DART_EXPORT void Dart_SetReturnValue(Dart_NativeArguments args,
Dart_Handle retval);
+DART_EXPORT void Dart_SetBooleanReturnValue(Dart_NativeArguments args,
+ bool retval);
+
+DART_EXPORT void Dart_SetIntegerReturnValue(Dart_NativeArguments args,
+ intptr_t retval);
+
+DART_EXPORT void Dart_SetDoubleReturnValue(Dart_NativeArguments args,
+ double retval);
+
/**
* A native function.
*/
diff --git a/runtime/lib/bool_patch.dart b/runtime/lib/bool_patch.dart
index fd84119..f5020c3 100644
--- a/runtime/lib/bool_patch.dart
+++ b/runtime/lib/bool_patch.dart
@@ -5,10 +5,9 @@
// Dart core library.
patch class bool {
-
- /* patch */ int get hashCode {
+
+ int get hashCode {
return this ? 1231 : 1237;
}
- /* patch */ bool operator ==(other) => identical(this, other);
}
diff --git a/runtime/lib/errors_patch.dart b/runtime/lib/errors_patch.dart
index 62148ac..c68ea47 100644
--- a/runtime/lib/errors_patch.dart
+++ b/runtime/lib/errors_patch.dart
@@ -178,9 +178,9 @@
}
}
-class _FiftyThreeBitOverflowError extends Error {
+class _JavascriptIntegerOverflowError extends Error {
final Object _value;
- _FiftyThreeBitOverflowError(this._value);
- String toString() => "53-bit Overflow: $_value";
+ _JavascriptIntegerOverflowError(this._value);
+ String toString() => "Javascript Integer Overflow: $_value";
}
diff --git a/runtime/lib/map_patch.dart b/runtime/lib/map_patch.dart
index cbc03fb..e723828 100644
--- a/runtime/lib/map_patch.dart
+++ b/runtime/lib/map_patch.dart
@@ -9,7 +9,7 @@
// in checked mode.
// The values are at position 2*n+1 and are not yet type checked.
factory Map._fromLiteral(List elements) {
- var map = new LinkedHashMap<String, V>();
+ var map = new LinkedHashMap<K, V>();
var len = elements.length;
for (int i = 1; i < len; i += 2) {
map[elements[i - 1]] = elements[i];
diff --git a/runtime/lib/mirror_reference.dart b/runtime/lib/mirror_reference.dart
index 7bdbc2d..b0f7726 100644
--- a/runtime/lib/mirror_reference.dart
+++ b/runtime/lib/mirror_reference.dart
@@ -7,4 +7,6 @@
throw new UnsupportedError(
"class _MirrorReference cannot be instantiated");
}
+
+ bool operator ==(other) native "MirrorReference_equals";
}
diff --git a/runtime/lib/mirrors.cc b/runtime/lib/mirrors.cc
index f9a1dcf..98806b1 100644
--- a/runtime/lib/mirrors.cc
+++ b/runtime/lib/mirrors.cc
@@ -2,19 +2,13 @@
// 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.
-#include "include/dart_api.h"
-#include "include/dart_debugger_api.h"
-#include "include/dart_mirrors_api.h"
-#include "vm/dart_api_impl.h"
-#include "vm/dart_api_state.h" // TODO(11742): Remove with CreateMirrorRef.
+#include "lib/invocation_mirror.h"
#include "vm/bootstrap_natives.h"
#include "vm/dart_entry.h"
#include "vm/exceptions.h"
-#include "vm/message.h"
+#include "vm/object_store.h"
#include "vm/port.h"
-#include "vm/resolver.h"
#include "vm/symbols.h"
-#include "lib/invocation_mirror.h"
namespace dart {
@@ -28,16 +22,11 @@
mirror_class_name,
constructor_name,
constructor_arguments));
- ASSERT(result.IsInstance());
+ ASSERT(!result.IsError());
return Instance::Cast(result).raw();
}
-inline Dart_Handle NewString(const char* str) {
- return Dart_NewStringFromCString(str);
-}
-
-
DEFINE_NATIVE_ENTRY(Mirrors_isLocalPort, 1) {
GET_NON_NULL_NATIVE_ARGUMENT(Instance, port, arguments->NativeArgAt(0));
@@ -55,51 +44,6 @@
}
-// TODO(turnidge): Add Map support to the dart embedding api instead
-// of implementing it here.
-static Dart_Handle CoreLib() {
- Dart_Handle core_lib_name = NewString("dart:core");
- return Dart_LookupLibrary(core_lib_name);
-}
-
-
-static Dart_Handle MapNew() {
- // TODO(turnidge): Switch to an order-preserving map type.
- Dart_Handle type = Dart_GetType(CoreLib(), NewString("Map"), 0, NULL);
- if (Dart_IsError(type)) {
- return type;
- }
- return Dart_New(type, Dart_Null(), 0, NULL);
-}
-
-
-static Dart_Handle MapAdd(Dart_Handle map, Dart_Handle key, Dart_Handle value) {
- Dart_Handle args[] = { key, value };
- return Dart_Invoke(map, NewString("[]="), ARRAY_SIZE(args), args);
-}
-
-
-static Dart_Handle MirrorLib() {
- Dart_Handle mirror_lib_name = NewString("dart:mirrors");
- return Dart_LookupLibrary(mirror_lib_name);
-}
-
-
-// TODO(11742): Remove once there are no more users of the Dart_Handle-based
-// VMReferences.
-static Dart_Handle CreateMirrorReference(Dart_Handle handle) {
- Isolate* isolate = Isolate::Current();
- DARTSCOPE(isolate);
- const Object& referent = Object::Handle(isolate, Api::UnwrapHandle(handle));
- const MirrorReference& reference =
- MirrorReference::Handle(MirrorReference::New(referent));
- return Api::NewHandle(isolate, reference.raw());
-}
-
-
-static Dart_Handle CreateLazyMirror(Dart_Handle target);
-
-
static RawInstance* CreateParameterMirrorList(const Function& func) {
HANDLESCOPE(Isolate::Current());
const intptr_t param_cnt = func.num_fixed_parameters() -
@@ -123,311 +67,74 @@
}
-static Dart_Handle CreateParameterMirrorListUsingApi(Dart_Handle func) {
- ASSERT(Dart_IsFunction(func));
- Isolate* isolate = Isolate::Current();
- return Api::NewHandle(
- isolate, CreateParameterMirrorList(Api::UnwrapFunctionHandle(
- isolate, func)));
-}
-
-
-static Dart_Handle CreateLazyMirror(Dart_Handle target) {
- if (Dart_IsNull(target) || Dart_IsError(target)) {
- return target;
- }
-
- if (Dart_IsLibrary(target)) {
- Dart_Handle cls_name = NewString("_LazyLibraryMirror");
- Dart_Handle type = Dart_GetType(MirrorLib(), cls_name, 0, NULL);
- Dart_Handle args[] = { Dart_LibraryUrl(target) };
- return Dart_New(type, Dart_Null(), ARRAY_SIZE(args), args);
- }
-
- if (Dart_IsClass(target)) {
- if (Dart_ClassIsFunctionType(target)) {
- Dart_Handle cls_name = NewString("_LazyFunctionTypeMirror");
- Dart_Handle type = Dart_GetType(MirrorLib(), cls_name, 0, NULL);
-
- Dart_Handle sig = Dart_ClassGetFunctionTypeSignature(target);
- Dart_Handle return_type = Dart_FunctionReturnType(sig);
- if (Dart_IsError(return_type)) {
- return return_type;
- }
-
- Dart_Handle args[] = {
- CreateLazyMirror(return_type),
- CreateParameterMirrorListUsingApi(sig),
- };
- return Dart_New(type, Dart_Null(), ARRAY_SIZE(args), args);
- } else {
- Dart_Handle cls_name = NewString("_LazyTypeMirror");
- Dart_Handle type = Dart_GetType(MirrorLib(), cls_name, 0, NULL);
- Dart_Handle lib = Dart_ClassGetLibrary(target);
- Dart_Handle lib_url;
- if (Dart_IsNull(lib)) {
- lib_url = Dart_Null();
- } else {
- lib_url = Dart_LibraryUrl(lib);
- }
- Dart_Handle args[] = { lib_url, Dart_ClassName(target) };
- return Dart_New(type, Dart_Null(), ARRAY_SIZE(args), args);
- }
- }
-
- if (Dart_IsTypeVariable(target)) {
- Dart_Handle var_name = Dart_TypeVariableName(target);
- Dart_Handle owner = Dart_TypeVariableOwner(target);
- Dart_Handle owner_mirror = CreateLazyMirror(owner);
-
- Dart_Handle cls_name = NewString("_LazyTypeVariableMirror");
- Dart_Handle type = Dart_GetType(MirrorLib(), cls_name, 0, NULL);
-
- Dart_Handle args[] = { var_name, owner_mirror };
- return Dart_New(type, Dart_Null(), ARRAY_SIZE(args), args);
- }
-
- UNREACHABLE();
- return Dart_Null();
-}
-
-
-static Dart_Handle CreateImplementsList(Dart_Handle intf) {
- intptr_t len = 0;
- Dart_Handle result = Dart_ClassGetInterfaceCount(intf, &len);
- if (Dart_IsError(result)) {
- return result;
- }
-
- Dart_Handle mirror_list = Dart_NewList(len);
- if (Dart_IsError(mirror_list)) {
- return mirror_list;
- }
-
- for (intptr_t i = 0; i < len; i++) {
- Dart_Handle interface = Dart_ClassGetInterfaceAt(intf, i);
- if (Dart_IsError(interface)) {
- return interface;
- }
- Dart_Handle mirror = CreateLazyMirror(interface);
- if (Dart_IsError(mirror)) {
- return mirror;
- }
- Dart_Handle result = Dart_ListSetAt(mirror_list, i, mirror);
- if (Dart_IsError(result)) {
- return result;
- }
- }
- return mirror_list;
-}
-
-
-static Dart_Handle CreateTypeVariableMirrorUsingApi(Dart_Handle type_var,
- Dart_Handle type_var_name,
- Dart_Handle owner_mirror) {
- ASSERT(Dart_IsTypeVariable(type_var));
- Dart_Handle cls_name = NewString("_LocalTypeVariableMirrorImpl");
- Dart_Handle type = Dart_GetType(MirrorLib(), cls_name, 0, NULL);
- if (Dart_IsError(type)) {
- return type;
- }
-
- Dart_Handle upper_bound = Dart_TypeVariableUpperBound(type_var);
- if (Dart_IsError(upper_bound)) {
- return upper_bound;
- }
-
- Dart_Handle args[] = {
- CreateMirrorReference(type_var),
- type_var_name,
- owner_mirror,
- CreateLazyMirror(upper_bound),
- };
- Dart_Handle mirror = Dart_New(type, Dart_Null(), ARRAY_SIZE(args), args);
- return mirror;
-}
-
-
static RawInstance* CreateTypeVariableMirror(const TypeParameter& param,
const Instance& owner_mirror) {
- Instance& retvalue = Instance::Handle();
- Dart_EnterScope();
- Isolate* isolate = Isolate::Current();
- Dart_Handle param_handle = Api::NewHandle(isolate, param.raw());
- if (Dart_IsError(param_handle)) {
- Dart_PropagateError(param_handle);
- }
- Dart_Handle name_handle = Api::NewHandle(isolate, param.Name());
- if (Dart_IsError(name_handle)) {
- Dart_PropagateError(name_handle);
- }
- // Until we get rid of lazy mirrors, we must have owners.
- Dart_Handle owner_handle;
- if (owner_mirror.IsNull()) {
- owner_handle = Api::NewHandle(isolate, param.parameterized_class());
- if (Dart_IsError(owner_handle)) {
- Dart_PropagateError(owner_handle);
- }
- owner_handle = CreateLazyMirror(owner_handle);
- if (Dart_IsError(owner_handle)) {
- Dart_PropagateError(owner_handle);
- }
- } else {
- owner_handle = Api::NewHandle(isolate, owner_mirror.raw());
- if (Dart_IsError(owner_handle)) {
- Dart_PropagateError(owner_handle);
- }
- }
- // TODO(11742): At some point the handle calls will be replaced by inlined
- // functionality.
- Dart_Handle result = CreateTypeVariableMirrorUsingApi(param_handle,
- name_handle,
- owner_handle);
- if (Dart_IsError(result)) {
- Dart_PropagateError(result);
- }
- retvalue ^= Api::UnwrapHandle(result);
- Dart_ExitScope();
- return retvalue.raw();
+ const Array& args = Array::Handle(Array::New(3));
+ args.SetAt(0, param);
+ args.SetAt(1, String::Handle(param.name()));
+ args.SetAt(2, owner_mirror);
+ return CreateMirror(Symbols::_LocalTypeVariableMirrorImpl(), args);
}
-static Dart_Handle CreateTypeVariableMap(Dart_Handle owner,
- Dart_Handle owner_mirror) {
- ASSERT(Dart_IsClass(owner));
- // TODO(turnidge): This should be an immutable map.
- Dart_Handle map = MapNew();
- if (Dart_IsError(map)) {
- return map;
+// We create a list in native code and let Dart code create the type mirror
+// object and the ordered map.
+static RawInstance* CreateTypeVariableList(const Class& cls) {
+ const TypeArguments& args = TypeArguments::Handle(cls.type_parameters());
+ if (args.IsNull()) {
+ return Object::empty_array().raw();
}
-
- Dart_Handle names = Dart_GetTypeVariableNames(owner);
- if (Dart_IsError(names)) {
- return names;
+ const Array& result = Array::Handle(Array::New(args.Length() * 2));
+ TypeParameter& type = TypeParameter::Handle();
+ String& name = String::Handle();
+ for (intptr_t i = 0; i < args.Length(); i++) {
+ type ^= args.TypeAt(i);
+ ASSERT(type.IsTypeParameter());
+ name ^= type.name();
+ result.SetAt(2 * i, name);
+ result.SetAt(2 * i + 1, type);
}
- intptr_t len;
- Dart_Handle result = Dart_ListLength(names, &len);
- if (Dart_IsError(result)) {
- return result;
- }
- for (intptr_t i = 0; i < len; i++) {
- Dart_Handle type_var_name = Dart_ListGetAt(names, i);
- Dart_Handle type_var = Dart_LookupTypeVariable(owner, type_var_name);
- if (Dart_IsError(type_var)) {
- return type_var;
- }
- ASSERT(!Dart_IsNull(type_var));
- Dart_Handle type_var_mirror =
- CreateTypeVariableMirrorUsingApi(type_var, type_var_name, owner_mirror);
- if (Dart_IsError(type_var_mirror)) {
- return type_var_mirror;
- }
- result = MapAdd(map, type_var_name, type_var_mirror);
- if (Dart_IsError(result)) {
- return result;
- }
- }
- return map;
+ return result.raw();
}
-static Dart_Handle CreateTypedefMirror(Dart_Handle cls,
- Dart_Handle cls_name,
- Dart_Handle owner_mirror) {
- Dart_Handle mirror_cls_name = NewString("_LocalTypedefMirrorImpl");
- Dart_Handle mirror_type = Dart_GetType(MirrorLib(), mirror_cls_name, 0, NULL);
- if (Dart_IsError(mirror_type)) {
- return mirror_type;
- }
-
- Dart_Handle referent = Dart_ClassGetTypedefReferent(cls);
- if (Dart_IsError(referent)) {
- return referent;
- }
-
- Dart_Handle args[] = {
- CreateMirrorReference(cls),
- cls_name,
- owner_mirror,
- CreateLazyMirror(referent),
- };
- Dart_Handle mirror =
- Dart_New(mirror_type, Dart_Null(), ARRAY_SIZE(args), args);
- return mirror;
+static RawInstance* CreateTypedefMirror(const Class& cls,
+ const Instance& owner_mirror) {
+ const Array& args = Array::Handle(Array::New(3));
+ args.SetAt(0, MirrorReference::Handle(MirrorReference::New(cls)));
+ args.SetAt(1, String::Handle(cls.UserVisibleName()));
+ args.SetAt(2, owner_mirror);
+ return CreateMirror(Symbols::_LocalTypedefMirrorImpl(), args);
}
-static Dart_Handle CreateClassMirrorUsingApi(Dart_Handle intf,
- Dart_Handle intf_name,
- Dart_Handle lib_mirror) {
- ASSERT(Dart_IsClass(intf));
- if (Dart_ClassIsTypedef(intf)) {
- // This class is actually a typedef. Represent it specially in
- // reflection.
- return CreateTypedefMirror(intf, intf_name, lib_mirror);
- }
-
- Dart_Handle cls_name = NewString("_LocalClassMirrorImpl");
- Dart_Handle type = Dart_GetType(MirrorLib(), cls_name, 0, NULL);
- if (Dart_IsError(type)) {
- return type;
- }
-
- Dart_Handle super_class = Dart_Null();
- // TODO(turnidge): Simplify code, now that default classes have been removed.
- Dart_Handle default_class = Dart_Null();
-
- Dart_Handle intf_mirror = CreateLazyMirror(intf);
- if (Dart_IsError(intf_mirror)) {
- return intf_mirror;
- }
- Dart_Handle type_var_map = CreateTypeVariableMap(intf, intf_mirror);
- if (Dart_IsError(type_var_map)) {
- return type_var_map;
- }
-
- Dart_Handle args[] = {
- CreateMirrorReference(intf),
- Dart_Null(), // "name"
- Dart_NewBoolean(Dart_IsClass(intf)),
- lib_mirror,
- super_class,
- CreateImplementsList(intf),
- CreateLazyMirror(default_class),
- type_var_map,
- };
- Dart_Handle mirror = Dart_New(type, Dart_Null(), ARRAY_SIZE(args), args);
- return mirror;
+static RawInstance* CreateFunctionTypeMirror(const Class& cls) {
+ const Array& args = Array::Handle(Array::New(1));
+ args.SetAt(0, MirrorReference::Handle(MirrorReference::New(cls)));
+ return CreateMirror(Symbols::_LocalFunctionTypeMirrorImpl(), args);
}
static RawInstance* CreateMethodMirror(const Function& func,
const Instance& owner_mirror) {
- const Array& args = Array::Handle(Array::New(11));
+ const Array& args = Array::Handle(Array::New(12));
args.SetAt(0, MirrorReference::Handle(MirrorReference::New(func)));
- args.SetAt(1, owner_mirror);
- args.SetAt(2, func.is_static() ? Bool::True() : Bool::False());
- args.SetAt(3, func.is_abstract() ? Bool::True() : Bool::False());
- args.SetAt(4, func.IsGetterFunction() ? Bool::True() : Bool::False());
- args.SetAt(5, func.IsSetterFunction() ? Bool::True() : Bool::False());
- args.SetAt(6, func.IsConstructor() ? Bool::True() : Bool::False());
+ args.SetAt(1, String::Handle(func.UserVisibleName()));
+ args.SetAt(2, owner_mirror);
+ args.SetAt(3, func.is_static() ? Bool::True() : Bool::False());
+ args.SetAt(4, func.is_abstract() ? Bool::True() : Bool::False());
+ args.SetAt(5, func.IsGetterFunction() ? Bool::True() : Bool::False());
+ args.SetAt(6, func.IsSetterFunction() ? Bool::True() : Bool::False());
+ args.SetAt(7, func.IsConstructor() ? Bool::True() : Bool::False());
// TODO(mlippautz): Implement different constructor kinds.
- args.SetAt(7, Bool::False());
args.SetAt(8, Bool::False());
args.SetAt(9, Bool::False());
args.SetAt(10, Bool::False());
+ args.SetAt(11, Bool::False());
return CreateMirror(Symbols::_LocalMethodMirrorImpl(), args);
}
-static Dart_Handle CreateMethodMirrorUsingApi(Dart_Handle func,
- Dart_Handle owner_mirror) {
- Isolate* isolate = Isolate::Current();
- return Api::NewHandle(isolate, CreateMethodMirror(
- Api::UnwrapFunctionHandle(isolate, func),
- Api::UnwrapInstanceHandle(isolate, owner_mirror)));
-}
-
static RawInstance* CreateVariableMirror(const Field& field,
const Instance& owner_mirror) {
const MirrorReference& field_ref =
@@ -447,224 +154,34 @@
}
-static Dart_Handle CreateLibraryMirrorUsingApi(Dart_Handle lib) {
- Dart_Handle cls_name = NewString("_LocalLibraryMirrorImpl");
- Dart_Handle type = Dart_GetType(MirrorLib(), cls_name, 0, NULL);
- if (Dart_IsError(type)) {
- return type;
- }
- Dart_Handle lazy_lib_mirror = CreateLazyMirror(lib);
- if (Dart_IsError(lazy_lib_mirror)) {
- return lazy_lib_mirror;
- }
- Dart_Handle args[] = {
- CreateMirrorReference(lib),
- Dart_LibraryName(lib),
- Dart_LibraryUrl(lib),
- };
- Dart_Handle lib_mirror = Dart_New(type, Dart_Null(), ARRAY_SIZE(args), args);
- if (Dart_IsError(lib_mirror)) {
- return lib_mirror;
- }
-
- return lib_mirror;
-}
-
-
-static Dart_Handle CreateLibrariesMap() {
- // TODO(turnidge): This should be an immutable map.
- Dart_Handle map = MapNew();
-
- Dart_Handle lib_ids = Dart_GetLibraryIds();
- if (Dart_IsError(lib_ids)) {
- return lib_ids;
- }
- intptr_t len;
- Dart_Handle result = Dart_ListLength(lib_ids, &len);
- if (Dart_IsError(result)) {
- return result;
- }
- for (intptr_t i = 0; i < len; i++) {
- Dart_Handle lib_id = Dart_ListGetAt(lib_ids, i);
- int64_t id64;
- Dart_IntegerToInt64(lib_id, &id64);
- Dart_Handle lib_url = Dart_GetLibraryURL(id64);
- if (Dart_IsError(lib_url)) {
- return lib_url;
- }
- Dart_Handle lib = Dart_LookupLibrary(lib_url);
- if (Dart_IsError(lib)) {
- return lib;
- }
- Dart_Handle lib_mirror = CreateLibraryMirrorUsingApi(lib);
- if (Dart_IsError(lib_mirror)) {
- return lib_mirror;
- }
- result = MapAdd(map, lib_url, lib_mirror);
- }
- return map;
-}
-
-
-static Dart_Handle CreateIsolateMirror() {
- Dart_Handle cls_name = NewString("_LocalIsolateMirrorImpl");
- Dart_Handle type = Dart_GetType(MirrorLib(), cls_name, 0, NULL);
- if (Dart_IsError(type)) {
- return type;
- }
- Dart_Handle args[] = {
- Dart_DebugName(),
- CreateLazyMirror(Dart_RootLibrary()),
- };
- return Dart_New(type, Dart_Null(), ARRAY_SIZE(args), args);
-}
-
-
-static Dart_Handle CreateMirrorSystem() {
- Dart_Handle cls_name = NewString("_LocalMirrorSystemImpl");
- Dart_Handle type = Dart_GetType(MirrorLib(), cls_name, 0, NULL);
- if (Dart_IsError(type)) {
- return type;
- }
-
- Dart_Handle libraries = CreateLibrariesMap();
- if (Dart_IsError(libraries)) {
- return libraries;
- }
-
- Dart_Handle args[] = {
- libraries,
- CreateIsolateMirror(),
- };
- Dart_Handle mirror = Dart_New(type, Dart_Null(), ARRAY_SIZE(args), args);
- if (Dart_IsError(mirror)) {
- return mirror;
- }
-
- return mirror;
-}
-
-
-static Dart_Handle CreateNullMirror() {
- Dart_Handle cls_name = NewString("_LocalInstanceMirrorImpl");
- Dart_Handle type = Dart_GetType(MirrorLib(), cls_name, 0, NULL);
- if (Dart_IsError(type)) {
- return type;
- }
-
- // TODO(turnidge): This is wrong. The Null class is distinct from object.
- Dart_Handle object_class = Dart_GetClass(CoreLib(), NewString("Object"));
-
- Dart_Handle args[] = {
- CreateLazyMirror(object_class),
- Dart_Null(),
- };
- Dart_Handle mirror = Dart_New(type, Dart_Null(), ARRAY_SIZE(args), args);
- return mirror;
-}
-
-
-static Dart_Handle CreateInstanceMirror(Dart_Handle instance) {
- if (Dart_IsNull(instance)) {
- return CreateNullMirror();
- }
- ASSERT(Dart_IsInstance(instance));
-
- Dart_Handle instance_cls = Dart_InstanceGetClass(instance);
- if (Dart_IsError(instance_cls)) {
- return instance_cls;
- }
-
- if (Dart_IsClosure(instance)) {
- Dart_Handle cls_name = NewString("_LocalClosureMirrorImpl");
- Dart_Handle type = Dart_GetType(MirrorLib(), cls_name, 0, NULL);
- if (Dart_IsError(type)) {
- return type;
- }
- // We set the function field of ClosureMirrors outside of the constructor
- // to break the mutual recursion.
- Dart_Handle func = Dart_ClosureFunction(instance);
- if (Dart_IsError(func)) {
- return func;
- }
-
- // TODO(turnidge): Why not use the real function name here?
- Dart_Handle func_owner = Dart_FunctionOwner(func);
- if (Dart_IsError(func_owner)) {
- return func_owner;
- }
-
- // TODO(turnidge): Pass the function owner here. This will require
- // us to support functions in CreateLazyMirror.
- Dart_Handle func_mirror =
- CreateMethodMirrorUsingApi(func, Dart_Null());
- if (Dart_IsError(func_mirror)) {
- return func_mirror;
- }
- Dart_Handle args[] = {
- CreateLazyMirror(instance_cls),
- instance,
- func_mirror,
- };
- return Dart_New(type, Dart_Null(), ARRAY_SIZE(args), args);
-
- } else {
- Dart_Handle cls_name = NewString("_LocalInstanceMirrorImpl");
- Dart_Handle type = Dart_GetType(MirrorLib(), cls_name, 0, NULL);
- if (Dart_IsError(type)) {
- return type;
- }
- Dart_Handle args[] = {
- CreateLazyMirror(instance_cls),
- instance,
- };
- return Dart_New(type, Dart_Null(), ARRAY_SIZE(args), args);
- }
-}
-
-
static RawInstance* CreateClassMirror(const Class& cls,
const Instance& owner_mirror) {
- Instance& retvalue = Instance::Handle();
- Dart_EnterScope();
- Isolate* isolate = Isolate::Current();
- Dart_Handle cls_handle = Api::NewHandle(isolate, cls.raw());
- if (Dart_IsError(cls_handle)) {
- Dart_PropagateError(cls_handle);
+ if (cls.IsSignatureClass()) {
+ if (cls.IsCanonicalSignatureClass()) {
+ // We represent function types as canonical signature classes.
+ return CreateFunctionTypeMirror(cls);
+ } else {
+ // We represent typedefs as non-canonical signature classes.
+ return CreateTypedefMirror(cls, owner_mirror);
+ }
}
- Dart_Handle name_handle = Api::NewHandle(isolate, cls.Name());
- if (Dart_IsError(name_handle)) {
- Dart_PropagateError(name_handle);
- }
- Dart_Handle lib_mirror = Api::NewHandle(isolate, owner_mirror.raw());
- // TODO(11742): At some point the handle calls will be replaced by inlined
- // functionality.
- Dart_Handle result = CreateClassMirrorUsingApi(cls_handle,
- name_handle,
- lib_mirror);
- if (Dart_IsError(result)) {
- Dart_PropagateError(result);
- }
- retvalue ^= Api::UnwrapHandle(result);
- Dart_ExitScope();
- return retvalue.raw();
+
+ const Array& args = Array::Handle(Array::New(2));
+ args.SetAt(0, MirrorReference::Handle(MirrorReference::New(cls)));
+ args.SetAt(1, String::Handle(cls.UserVisibleName()));
+ return CreateMirror(Symbols::_LocalClassMirrorImpl(), args);
}
static RawInstance* CreateLibraryMirror(const Library& lib) {
- Instance& retvalue = Instance::Handle();
- Dart_EnterScope();
- Isolate* isolate = Isolate::Current();
- Dart_Handle lib_handle = Api::NewHandle(isolate, lib.raw());
- // TODO(11742): At some point the handle calls will be replaced by inlined
- // functionality.
- Dart_Handle result = CreateLibraryMirrorUsingApi(lib_handle);
- if (Dart_IsError(result)) {
- Dart_PropagateError(result);
- }
- retvalue ^= Api::UnwrapHandle(result);
- Dart_ExitScope();
- return retvalue.raw();
+ const Array& args = Array::Handle(Array::New(3));
+ args.SetAt(0, MirrorReference::Handle(MirrorReference::New(lib)));
+ String& str = String::Handle();
+ str = lib.name();
+ args.SetAt(1, str);
+ str = lib.url();
+ args.SetAt(2, str);
+ return CreateMirror(Symbols::_LocalLibraryMirrorImpl(), args);
}
@@ -694,58 +211,55 @@
}
-void NATIVE_ENTRY_FUNCTION(Mirrors_makeLocalMirrorSystem)(
- Dart_NativeArguments args) {
- Dart_EnterScope();
- Dart_Handle mirrors = CreateMirrorSystem();
- if (Dart_IsError(mirrors)) {
- Dart_PropagateError(mirrors);
- }
- Dart_SetReturnValue(args, mirrors);
- Dart_ExitScope();
-}
-
-
-void NATIVE_ENTRY_FUNCTION(Mirrors_makeLocalInstanceMirror)(
- Dart_NativeArguments args) {
- Dart_EnterScope();
- Dart_Handle reflectee = Dart_GetNativeArgument(args, 0);
- Dart_Handle mirror = CreateInstanceMirror(reflectee);
- if (Dart_IsError(mirror)) {
- Dart_PropagateError(mirror);
- }
- Dart_SetReturnValue(args, mirror);
- Dart_ExitScope();
-}
-
-
-void NATIVE_ENTRY_FUNCTION(Mirrors_makeLocalClassMirror)(
- Dart_NativeArguments args) {
- Dart_EnterScope();
+static RawInstance* CreateIsolateMirror() {
Isolate* isolate = Isolate::Current();
- Dart_Handle key = Dart_GetNativeArgument(args, 0);
- if (Dart_IsError(key)) {
- Dart_PropagateError(key);
+ const String& debug_name = String::Handle(String::New(isolate->name()));
+ const Library& root_library =
+ Library::Handle(isolate, isolate->object_store()->root_library());
+ const Instance& root_library_mirror =
+ Instance::Handle(CreateLibraryMirror(root_library));
+
+ const Array& args = Array::Handle(Array::New(2));
+ args.SetAt(0, debug_name);
+ args.SetAt(1, root_library_mirror);
+ return CreateMirror(Symbols::_LocalIsolateMirrorImpl(), args);
+}
+
+
+static RawInstance* CreateMirrorSystem() {
+ Isolate* isolate = Isolate::Current();
+ const GrowableObjectArray& libraries =
+ GrowableObjectArray::Handle(isolate->object_store()->libraries());
+
+ const int num_libraries = libraries.Length();
+ const Array& library_mirrors = Array::Handle(Array::New(num_libraries));
+ Library& library = Library::Handle();
+ Instance& library_mirror = Instance::Handle();
+
+ for (int i = 0; i < num_libraries; i++) {
+ library ^= libraries.At(i);
+ library_mirror = CreateLibraryMirror(library);
+ library_mirrors.SetAt(i, library_mirror);
}
- const Type& type = Api::UnwrapTypeHandle(isolate, key);
+
+ const Instance& isolate_mirror = Instance::Handle(CreateIsolateMirror());
+
+ const Array& args = Array::Handle(Array::New(2));
+ args.SetAt(0, library_mirrors);
+ args.SetAt(1, isolate_mirror);
+ return CreateMirror(Symbols::_LocalMirrorSystemImpl(), args);
+}
+
+
+DEFINE_NATIVE_ENTRY(Mirrors_makeLocalMirrorSystem, 0) {
+ return CreateMirrorSystem();
+}
+
+
+DEFINE_NATIVE_ENTRY(Mirrors_makeLocalClassMirror, 1) {
+ GET_NON_NULL_NATIVE_ARGUMENT(Type, type, arguments->NativeArgAt(0));
const Class& cls = Class::Handle(type.type_class());
- Dart_Handle cls_handle = Api::NewHandle(isolate, cls.raw());
- if (Dart_IsError(cls_handle)) {
- Dart_PropagateError(cls_handle);
- }
- Dart_Handle name_handle = Api::NewHandle(isolate, cls.Name());
- if (Dart_IsError(name_handle)) {
- Dart_PropagateError(name_handle);
- }
- Dart_Handle lib_mirror = Dart_Null();
- Dart_Handle result = CreateClassMirrorUsingApi(cls_handle,
- name_handle,
- lib_mirror);
- if (Dart_IsError(result)) {
- Dart_PropagateError(result);
- }
- Dart_SetReturnValue(args, result);
- Dart_ExitScope();
+ return CreateClassMirror(cls, Object::null_instance());
}
@@ -771,6 +285,13 @@
}
+DEFINE_NATIVE_ENTRY(MirrorReference_equals, 2) {
+ GET_NON_NULL_NATIVE_ARGUMENT(MirrorReference, a, arguments->NativeArgAt(0));
+ GET_NON_NULL_NATIVE_ARGUMENT(MirrorReference, b, arguments->NativeArgAt(1));
+ return Bool::Get(a.referent() == b.referent());
+}
+
+
DEFINE_NATIVE_ENTRY(DeclarationMirror_metadata, 1) {
const MirrorReference& decl_ref =
MirrorReference::CheckedHandle(arguments->NativeArgAt(0));
@@ -796,10 +317,20 @@
}
-void HandleMirrorsMessage(Isolate* isolate,
- Dart_Port reply_port,
- const Instance& message) {
- UNIMPLEMENTED();
+DEFINE_NATIVE_ENTRY(FunctionTypeMirror_parameters, 1) {
+ GET_NON_NULL_NATIVE_ARGUMENT(MirrorReference, ref, arguments->NativeArgAt(0));
+ const Class& cls = Class::Handle(ref.GetClassReferent());
+ const Function& func = Function::Handle(cls.signature_function());
+ return CreateParameterMirrorList(func);
+}
+
+
+DEFINE_NATIVE_ENTRY(FunctionTypeMirror_return_type, 1) {
+ GET_NON_NULL_NATIVE_ARGUMENT(MirrorReference, ref, arguments->NativeArgAt(0));
+ const Class& cls = Class::Handle(ref.GetClassReferent());
+ const Function& func = Function::Handle(cls.signature_function());
+ const AbstractType& return_type = AbstractType::Handle(func.result_type());
+ return CreateTypeMirror(return_type);
}
@@ -835,6 +366,20 @@
return klass.super_type();
}
+
+DEFINE_NATIVE_ENTRY(ClassMirror_interfaces, 1) {
+ GET_NON_NULL_NATIVE_ARGUMENT(MirrorReference, ref, arguments->NativeArgAt(0));
+ const Class& klass = Class::Handle(ref.GetClassReferent());
+
+ const Error& error = Error::Handle(klass.EnsureIsFinalized(isolate));
+ if (!error.IsNull()) {
+ ThrowInvokeError(error);
+ }
+
+ return klass.interfaces();
+}
+
+
DEFINE_NATIVE_ENTRY(ClassMirror_members, 2) {
GET_NON_NULL_NATIVE_ARGUMENT(Instance,
owner_mirror,
@@ -965,6 +510,26 @@
}
+DEFINE_NATIVE_ENTRY(ClassMirror_type_variables, 1) {
+ GET_NON_NULL_NATIVE_ARGUMENT(MirrorReference, ref, arguments->NativeArgAt(0));
+ const Class& klass = Class::Handle(ref.GetClassReferent());
+ return CreateTypeVariableList(klass);
+}
+
+
+DEFINE_NATIVE_ENTRY(LocalTypeVariableMirror_owner, 1) {
+ GET_NON_NULL_NATIVE_ARGUMENT(TypeParameter, param, arguments->NativeArgAt(0));
+ return CreateClassMirror(Class::Handle(param.parameterized_class()),
+ Instance::null_instance());
+}
+
+
+DEFINE_NATIVE_ENTRY(LocalTypeVariableMirror_upper_bound, 1) {
+ GET_NON_NULL_NATIVE_ARGUMENT(TypeParameter, param, arguments->NativeArgAt(0));
+ return CreateTypeMirror(AbstractType::Handle(param.bound()));
+}
+
+
// Invoke the function, or noSuchMethod if it is null. Propagate any unhandled
// exceptions. Wrap and propagate any compilation errors.
static RawObject* ReflectivelyInvokeDynamicFunction(const Instance& receiver,
@@ -1016,11 +581,21 @@
ArgumentsDescriptor args_desc(
Array::Handle(ArgumentsDescriptor::New(args.Length())));
- // TODO(11771): This won't find private members.
- const Function& function = Function::Handle(
- Resolver::ResolveDynamic(reflectee,
- function_name,
- args_desc));
+
+ Class& klass = Class::Handle(reflectee.clazz());
+ Function& function = Function::Handle();
+ while (!klass.IsNull()) {
+ function = klass.LookupDynamicFunctionAllowPrivate(function_name);
+ if (!function.IsNull()) {
+ break;
+ }
+ klass = klass.SuperClass();
+ }
+
+ if (!function.IsNull() &&
+ !function.AreValidArguments(args_desc, NULL)) {
+ function = Function::null();
+ }
return ReflectivelyInvokeDynamicFunction(reflectee,
function,
@@ -1134,6 +709,15 @@
}
+DEFINE_NATIVE_ENTRY(ClosureMirror_function, 1) {
+ GET_NON_NULL_NATIVE_ARGUMENT(Instance, closure, arguments->NativeArgAt(0));
+ ASSERT(closure.IsClosure());
+
+ const Function& func = Function::Handle(Closure::function(closure));
+ return CreateMethodMirror(func, Instance::null_instance());
+}
+
+
static void ThrowNoSuchMethod(const Instance& receiver,
const String& function_name,
const Function& function,
@@ -1544,13 +1128,6 @@
}
-DEFINE_NATIVE_ENTRY(MethodMirror_name, 1) {
- GET_NON_NULL_NATIVE_ARGUMENT(MirrorReference, ref, arguments->NativeArgAt(0));
- const Function& func = Function::Handle(ref.GetFunctionReferent());
- return func.UserVisibleName();
-}
-
-
DEFINE_NATIVE_ENTRY(MethodMirror_owner, 1) {
GET_NON_NULL_NATIVE_ARGUMENT(MirrorReference, ref, arguments->NativeArgAt(0));
const Function& func = Function::Handle(ref.GetFunctionReferent());
@@ -1583,6 +1160,15 @@
}
+DEFINE_NATIVE_ENTRY(TypedefMirror_referent, 1) {
+ GET_NON_NULL_NATIVE_ARGUMENT(MirrorReference, ref, arguments->NativeArgAt(0));
+ const Class& cls = Class::Handle(ref.GetClassReferent());
+ const Function& sig_func = Function::Handle(cls.signature_function());
+ const Class& sig_cls = Class::Handle(sig_func.signature_class());
+ return MirrorReference::New(sig_cls);
+}
+
+
DEFINE_NATIVE_ENTRY(ParameterMirror_type, 2) {
GET_NON_NULL_NATIVE_ARGUMENT(MirrorReference, ref, arguments->NativeArgAt(0));
GET_NON_NULL_NATIVE_ARGUMENT(Smi, pos, arguments->NativeArgAt(1));
diff --git a/runtime/lib/mirrors_impl.dart b/runtime/lib/mirrors_impl.dart
index 80d2ea4..5fb76c7 100644
--- a/runtime/lib/mirrors_impl.dart
+++ b/runtime/lib/mirrors_impl.dart
@@ -4,6 +4,8 @@
// VM-specific implementation of the dart:mirrors library.
+import "dart:collection";
+
// These values are allowed to be passed directly over the wire.
bool _isSimpleValue(var value) {
return (value == null || value is num || value is String || value is bool);
@@ -68,12 +70,10 @@
return buf.toString();
}
-Map<Uri, LibraryMirror> _createLibrariesMap(Map<String, LibraryMirror> map) {
- var result = new Map<Uri, LibraryMirror>();
- map.forEach((String url, LibraryMirror mirror) {
- result[Uri.parse(url)] = mirror;
- });
- return result;
+Map<Uri, LibraryMirror> _createLibrariesMap(List<LibraryMirror> list) {
+ var map = new Map<Uri, LibraryMirror>();
+ list.forEach((LibraryMirror mirror) => map[mirror.uri] = mirror);
+ return map;
}
List _metadata(reflectee)
@@ -98,9 +98,8 @@
class _LocalMirrorSystemImpl extends MirrorSystem {
// Change parameter back to "this.libraries" when native code is changed.
- _LocalMirrorSystemImpl(Map<String, LibraryMirror> libraries, this.isolate)
- : this.libraries = _createLibrariesMap(libraries),
- _functionTypes = new Map<String, FunctionTypeMirror>();
+ _LocalMirrorSystemImpl(List<LibraryMirror> libraries, this.isolate)
+ : this.libraries = _createLibrariesMap(libraries);
final Map<Uri, LibraryMirror> libraries;
final IsolateMirror isolate;
@@ -123,22 +122,6 @@
return _voidType;
}
- final Map<String, FunctionTypeMirror> _functionTypes;
- FunctionTypeMirror _lookupFunctionTypeMirror(
- TypeMirror returnType,
- List<ParameterMirror> parameters) {
- var sigString = _makeSignatureString(returnType, parameters);
- var mirror = _functionTypes[sigString];
- if (mirror == null) {
- mirror = new _LocalFunctionTypeMirrorImpl(null,
- sigString,
- returnType,
- parameters);
- _functionTypes[sigString] = mirror;
- }
- return mirror;
- }
-
String toString() => "MirrorSystem for isolate '${isolate.debugName}'";
}
@@ -154,18 +137,11 @@
class _LocalIsolateMirrorImpl extends _LocalMirrorImpl
implements IsolateMirror {
- _LocalIsolateMirrorImpl(this.debugName, this._rootLibrary) {}
+ _LocalIsolateMirrorImpl(this.debugName, this.rootLibrary) {}
final String debugName;
final bool isCurrent = true;
-
- var _rootLibrary;
- LibraryMirror get rootLibrary {
- if (_rootLibrary is _LazyLibraryMirror) {
- _rootLibrary = _rootLibrary.resolve(mirrors);
- }
- return _rootLibrary;
- }
+ final LibraryMirror rootLibrary;
String toString() => "IsolateMirror on '$debugName'";
}
@@ -268,13 +244,14 @@
// TODO(ahe): This is a hack, see delegate below.
static Function _invokeOnClosure;
- _LocalInstanceMirrorImpl(this._type,
- reflectee) : super(reflectee) {}
+ _LocalInstanceMirrorImpl(reflectee) : super(reflectee);
- var _type;
+ ClassMirror _type;
ClassMirror get type {
- if (_type is! Mirror) {
- _type = _type.resolve(mirrors);
+ if (_type == null) {
+ // Note it not safe to use reflectee.runtimeType because runtimeType may
+ // be overridden.
+ _type = reflectClass(_computeType(reflectee));
}
return _type;
}
@@ -292,15 +269,22 @@
// private method does not work.
_LocalInstanceMirrorImpl mirror =
- _Mirrors.makeLocalInstanceMirror(invocation);
- _invokeOnClosure =
- reflectClass(invocation.runtimeType).getField(const Symbol('_invokeOnClosure')).reflectee;
+ reflect(invocation);
+ _invokeOnClosure = reflectClass(invocation.runtimeType)
+ .getField(const Symbol('_invokeOnClosure')).reflectee;
}
return _invokeOnClosure(reflectee, invocation);
}
String toString() => 'InstanceMirror on ${Error.safeToString(_reflectee)}';
+ bool operator ==(other) {
+ return other is _LocalInstanceMirrorImpl &&
+ identical(_reflectee, other._reflectee);
+ }
+
+ int get hashCode => _reflectee.hashCode;
+
_invoke(reflectee, functionName, positionalArguments)
native 'InstanceMirror_invoke';
@@ -309,15 +293,22 @@
_invokeSetter(reflectee, setterName, value)
native 'InstanceMirror_invokeSetter';
+
+ static _computeType(reflectee)
+ native 'Object_runtimeType';
}
class _LocalClosureMirrorImpl extends _LocalInstanceMirrorImpl
implements ClosureMirror {
- _LocalClosureMirrorImpl(type,
- reflectee,
- this.function) : super(type, reflectee) {}
+ _LocalClosureMirrorImpl(reflectee) : super(reflectee);
- final MethodMirror function;
+ MethodMirror _function;
+ MethodMirror get function {
+ if (_function == null) {
+ _function = _computeFunction(reflectee);
+ }
+ return _function;
+ }
String get source {
throw new UnimplementedError(
@@ -352,58 +343,25 @@
}
}
-
-
Future<InstanceMirror> findInContext(Symbol name) {
throw new UnimplementedError(
'ClosureMirror.findInContext() is not implemented');
}
+ String toString() => "ClosureMirror on '${Error.safeToString(_reflectee)}'";
+
static _apply(reflectee, positionalArguments)
native 'ClosureMirror_apply';
- String toString() => "ClosureMirror on '${Error.safeToString(_reflectee)}'";
-}
-
-class _LazyTypeMirror {
- _LazyTypeMirror(String this.libraryUrl, String typeName)
- : this.typeName = _s(typeName);
-
- TypeMirror resolve(MirrorSystem mirrors) {
- if (libraryUrl == null) {
- if (typeName == const Symbol('dynamic')) {
- return mirrors.dynamicType;
- } else if (typeName == const Symbol('void')) {
- return mirrors.voidType;
- } else {
- throw new UnimplementedError(
- "Mirror for type '$typeName' is not implemented");
- }
- }
- var resolved = mirrors.libraries[Uri.parse(libraryUrl)].members[typeName];
- if (resolved == null) {
- throw new UnimplementedError(
- "Mirror for type '$typeName' is not implemented");
- }
- return resolved;
- }
-
- final String libraryUrl;
- final Symbol typeName;
+ static _computeFunction(reflectee)
+ native 'ClosureMirror_function';
}
class _LocalClassMirrorImpl extends _LocalObjectMirrorImpl
implements ClassMirror {
_LocalClassMirrorImpl(reflectee,
- String simpleName,
- this.isClass,
- this._owner,
- this._superclass,
- this._superinterfaces,
- this._defaultFactory,
- Map<String, Mirror> typeVariables)
+ String simpleName)
: this._simpleName = _s(simpleName),
- this.typeVariables = _convertStringToSymbolMap(typeVariables),
super(reflectee);
Symbol _simpleName;
@@ -429,9 +387,6 @@
if (_owner == null) {
_owner = _library(_reflectee);
}
- if (_owner is! Mirror) {
- _owner = _owner.resolve(mirrors);
- }
return _owner;
}
@@ -444,9 +399,12 @@
'ClassMirror.location is not implemented');
}
- final bool isClass;
+ // TODO(rmacnak): Remove these left-overs from the days of separate interfaces
+ // once we send out a breaking change.
+ bool get isClass => true;
+ ClassMirror get defaultFactory => null;
- var _superclass;
+ ClassMirror _superclass;
ClassMirror get superclass {
if (_superclass == null) {
Type supertype = _supertype(_reflectee);
@@ -456,33 +414,18 @@
}
_superclass = reflectClass(supertype);
}
- if (_superclass is! Mirror) {
- _superclass = _superclass.resolve(mirrors);
- }
return _superclass;
}
var _superinterfaces;
List<ClassMirror> get superinterfaces {
- if (_superinterfaces.length > 0 &&
- _superinterfaces[0] is! Mirror) {
- List<ClassMirror> resolved = new List<ClassMirror>();
- for (int i = 0; i < _superinterfaces.length; i++) {
- resolved.add(_superinterfaces[i].resolve(mirrors));
- }
- _superinterfaces = resolved;
+ if (_superinterfaces == null) {
+ _superinterfaces = _interfaces(_reflectee)
+ .map((i) => reflectClass(i)).toList(growable:false);
}
return _superinterfaces;
}
- var _defaultFactory;
- ClassMirror get defaultFactory {
- if (_defaultFactory != null && _defaultFactory is! Mirror) {
- _defaultFactory = _defaultFactory.resolve(mirrors);
- }
- return _defaultFactory;
- }
-
Map<Symbol, Mirror> _members;
Map<Symbol, Mirror> get members {
@@ -542,7 +485,21 @@
return _constructors;
}
- Map<Symbol, TypeVariableMirror> typeVariables;
+ Map<Symbol, TypeVariableMirror> _typeVariables = null;
+
+ Map<Symbol, TypeVariableMirror> get typeVariables {
+ if (_typeVariables == null) {
+ List params = _ClassMirror_type_variables(_reflectee);
+ _typeVariables = new LinkedHashMap<Symbol, TypeVariableMirror>();
+ var mirror;
+ for (var i = 0; i < params.length; i += 2) {
+ mirror = new _LocalTypeVariableMirrorImpl(
+ params[i + 1], params[i], this);
+ _typeVariables[mirror.simpleName] = mirror;
+ }
+ }
+ return _typeVariables;
+ }
Map<Symbol, TypeMirror> get typeArguments {
throw new UnimplementedError(
@@ -560,8 +517,7 @@
}
String toString() {
- String prettyName = isClass ? 'ClassMirror' : 'TypeMirror';
- return "$prettyName on '${_n(simpleName)}'";
+ return "ClassMirror on '${_n(simpleName)}'";
}
InstanceMirror newInstance(Symbol constructorName,
@@ -600,6 +556,13 @@
return _metadata(_reflectee).map(reflect).toList(growable:false);
}
+ bool operator ==(other) {
+ return this.runtimeType == other.runtimeType &&
+ this._reflectee == other._reflectee;
+ }
+
+ int get hashCode => simpleName.hashCode;
+
static _name(reflectee)
native "ClassMirror_name";
@@ -609,6 +572,9 @@
static _supertype(reflectee)
native "ClassMirror_supertype";
+ static _interfaces(reflectee)
+ native "ClassMirror_interfaces";
+
_computeMembers(reflectee)
native "ClassMirror_members";
@@ -626,84 +592,58 @@
static _invokeConstructor(reflectee, constructorName, positionalArguments)
native 'ClassMirror_invokeConstructor';
-}
-class _LazyFunctionTypeMirror {
- _LazyFunctionTypeMirror(this.returnType, this.parameters) {}
-
- ClassMirror resolve(MirrorSystem mirrors) {
- return mirrors._lookupFunctionTypeMirror(returnType.resolve(mirrors),
- parameters);
- }
-
- final returnType;
- final List<ParameterMirror> parameters;
+ static _ClassMirror_type_variables(reflectee)
+ native "ClassMirror_type_variables";
}
class _LocalFunctionTypeMirrorImpl extends _LocalClassMirrorImpl
implements FunctionTypeMirror {
- _LocalFunctionTypeMirrorImpl(reflectee,
- simpleName,
- this._returnType,
- this.parameters)
- : super(reflectee,
- simpleName,
- true,
- null,
- new _LazyTypeMirror('dart:core', 'Object'),
- [ new _LazyTypeMirror('dart:core', 'Function') ],
- null,
- const {});
+ _LocalFunctionTypeMirrorImpl(reflectee) : super(reflectee, null);
- Map<Symbol, Mirror> get members => new Map<Symbol,Mirror>();
- Map<Symbol, MethodMirror> get constructors => new Map<Symbol,MethodMirror>();
+ // FunctionTypeMirrors have a simpleName generated from their signature.
+ Symbol _simpleName = null;
+ Symbol get simpleName {
+ if (_simpleName == null) {
+ _simpleName = _s(_makeSignatureString(returnType, parameters));
+ }
+ return _simpleName;
+ }
- var _returnType;
+ TypeMirror _returnType = null;
TypeMirror get returnType {
- if (_returnType is! Mirror) {
- _returnType = _returnType.resolve(mirrors);
+ if (_returnType == null) {
+ _returnType = _FunctionTypeMirror_return_type(_reflectee);
}
return _returnType;
}
- final List<ParameterMirror> parameters;
+ List<ParameterMirror> _parameters = null;
+ List<ParameterMirror> get parameters {
+ if (_parameters == null) {
+ _parameters = _FunctionTypeMirror_parameters(_reflectee);
+ }
+ return _parameters;
+ }
+
+ Map<Symbol, Mirror> get members => new Map<Symbol,Mirror>();
+ Map<Symbol, MethodMirror> get constructors => new Map<Symbol,MethodMirror>();
+ final Map<Symbol, TypeVariableMirror> typeVariables = const {};
String toString() => "FunctionTypeMirror on '${_n(simpleName)}'";
+
+ static TypeMirror _FunctionTypeMirror_return_type(reflectee)
+ native "FunctionTypeMirror_return_type";
+
+ static List<ParameterMirror> _FunctionTypeMirror_parameters(reflectee)
+ native "FunctionTypeMirror_parameters";
}
abstract class _LocalDeclarationMirrorImpl extends _LocalMirrorImpl
implements DeclarationMirror {
- _LocalDeclarationMirrorImpl(this._reflectee);
- final _MirrorReference _reflectee;
+ _LocalDeclarationMirrorImpl(this._reflectee, this.simpleName);
- List<InstanceMirror> get metadata {
- // Get the metadata objects, convert them into InstanceMirrors using
- // reflect() and then make them into a Dart list.
- return _metadata(_reflectee).map(reflect).toList(growable:false);
- }
-}
-
-class _LazyTypeVariableMirror {
- _LazyTypeVariableMirror(String variableName, this._owner)
- : this._variableName = _s(variableName);
-
- TypeVariableMirror resolve(MirrorSystem mirrors) {
- ClassMirror owner = _owner.resolve(mirrors);
- return owner.typeVariables[_variableName];
- }
-
- final Symbol _variableName;
- final _LazyTypeMirror _owner;
-}
-
-class _LocalTypeVariableMirrorImpl extends _LocalDeclarationMirrorImpl
- implements TypeVariableMirror {
- _LocalTypeVariableMirrorImpl(reflectee,
- String simpleName,
- this._owner,
- this._upperBound)
- : this.simpleName = _s(simpleName),
- super(reflectee);
+ final _reflectee;
final Symbol simpleName;
@@ -715,10 +655,31 @@
return _qualifiedName;
}
- var _owner;
+ List<InstanceMirror> get metadata {
+ // Get the metadata objects, convert them into InstanceMirrors using
+ // reflect() and then make them into a Dart list.
+ return _metadata(_reflectee).map(reflect).toList(growable:false);
+ }
+
+ bool operator ==(other) {
+ return this.runtimeType == other.runtimeType &&
+ this._reflectee == other._reflectee;
+ }
+
+ int get hashCode => simpleName.hashCode;
+}
+
+class _LocalTypeVariableMirrorImpl extends _LocalDeclarationMirrorImpl
+ implements TypeVariableMirror {
+ _LocalTypeVariableMirrorImpl(reflectee,
+ String simpleName,
+ this._owner)
+ : super(reflectee, _s(simpleName));
+
+ DeclarationMirror _owner;
DeclarationMirror get owner {
- if (_owner is! Mirror) {
- _owner = _owner.resolve(mirrors);
+ if (_owner == null) {
+ _owner = _LocalTypeVariableMirror_owner(_reflectee);
}
return _owner;
}
@@ -732,10 +693,10 @@
'TypeVariableMirror.location is not implemented');
}
- var _upperBound;
+ TypeMirror _upperBound = null;
TypeMirror get upperBound {
- if (_upperBound is! Mirror) {
- _upperBound = _upperBound.resolve(mirrors);
+ if (_upperBound == null) {
+ _upperBound = _LocalTypeVariableMirror_upper_bound(_reflectee);
}
return _upperBound;
}
@@ -746,6 +707,12 @@
}
String toString() => "TypeVariableMirror on '${_n(simpleName)}'";
+
+ static DeclarationMirror _LocalTypeVariableMirror_owner(reflectee)
+ native "LocalTypeVariableMirror_owner";
+
+ static TypeMirror _LocalTypeVariableMirror_upper_bound(reflectee)
+ native "LocalTypeVariableMirror_upper_bound";
}
@@ -753,29 +720,14 @@
implements TypedefMirror {
_LocalTypedefMirrorImpl(reflectee,
String simpleName,
- this._owner,
- this._referent)
- : this.simpleName = _s(simpleName),
- super(reflectee);
+ this._owner)
+ : super(reflectee, _s(simpleName));
- final Symbol simpleName;
-
- Symbol _qualifiedName = null;
- Symbol get qualifiedName {
- if (_qualifiedName == null) {
- _qualifiedName = _computeQualifiedName(owner, simpleName);
- }
- return _qualifiedName;
- }
-
- var _owner;
+ DeclarationMirror _owner;
DeclarationMirror get owner {
if (_owner == null) {
_owner = _LocalClassMirrorImpl._library(_reflectee);
}
- if (_owner is! Mirror) {
- _owner = _owner.resolve(mirrors);
- }
return _owner;
}
@@ -788,26 +740,19 @@
'TypedefMirror.location is not implemented');
}
- var _referent;
+ TypeMirror _referent = null;
TypeMirror get referent {
- if (_referent is! Mirror) {
- _referent = _referent.resolve(mirrors);
+ if (_referent == null) {
+ return new _LocalFunctionTypeMirrorImpl(
+ _TypedefMirror_referent(_reflectee));
}
return _referent;
}
String toString() => "TypedefMirror on '${_n(simpleName)}'";
-}
-
-class _LazyLibraryMirror {
- _LazyLibraryMirror(String this.libraryUrl);
-
- LibraryMirror resolve(MirrorSystem mirrors) {
- return mirrors.libraries[Uri.parse(libraryUrl)];
- }
-
- final String libraryUrl;
+ static _TypedefMirror_referent(_reflectee)
+ native "TypedefMirror_referent";
}
class _LocalLibraryMirrorImpl extends _LocalObjectMirrorImpl
@@ -903,6 +848,13 @@
String toString() => "LibraryMirror on '${_n(simpleName)}'";
+ bool operator ==(other) {
+ return this.runtimeType == other.runtimeType &&
+ this._reflectee == other._reflectee;
+ }
+
+ int get hashCode => simpleName.hashCode;
+
_invoke(reflectee, memberName, positionalArguments)
native 'LibraryMirror_invoke';
@@ -919,6 +871,7 @@
class _LocalMethodMirrorImpl extends _LocalDeclarationMirrorImpl
implements MethodMirror {
_LocalMethodMirrorImpl(reflectee,
+ String simpleName,
this._owner,
this.isStatic,
this.isAbstract,
@@ -928,35 +881,16 @@
this.isConstConstructor,
this.isGenerativeConstructor,
this.isRedirectingConstructor,
- this.isFactoryConstructor) : super(reflectee);
+ this.isFactoryConstructor)
+ : super(reflectee, _s(simpleName));
- Symbol _simpleName = null;
- Symbol get simpleName {
- if (_simpleName == null) {
- _simpleName = _s(_MethodMirror_name(_reflectee));
- }
- return _simpleName;
- }
-
- Symbol _qualifiedName = null;
- Symbol get qualifiedName {
- if (_qualifiedName == null) {
- _qualifiedName = _computeQualifiedName(owner, simpleName);
- }
- return _qualifiedName;
- }
-
- var _owner;
+ DeclarationMirror _owner;
DeclarationMirror get owner {
// For nested closures it is possible, that the mirror for the owner has not
// been created yet.
if (_owner == null) {
_owner = _MethodMirror_owner(_reflectee);
}
- // TODO(11897): This will go away, as soon as lazy mirrors go away.
- if (_owner is! Mirror) {
- _owner = _owner.resolve(mirrors);
- }
return _owner;
}
@@ -1034,9 +968,6 @@
String toString() => "MethodMirror on '${_n(simpleName)}'";
- static String _MethodMirror_name(reflectee)
- native "MethodMirror_name";
-
static dynamic _MethodMirror_owner(reflectee)
native "MethodMirror_owner";
@@ -1051,30 +982,13 @@
implements VariableMirror {
_LocalVariableMirrorImpl(reflectee,
String simpleName,
- this._owner,
+ this.owner,
this._type,
this.isStatic,
this.isFinal)
- : this.simpleName = _s(simpleName),
- super(reflectee);
+ : super(reflectee, _s(simpleName));
- final Symbol simpleName;
-
- Symbol _qualifiedName = null;
- Symbol get qualifiedName {
- if (_qualifiedName == null) {
- _qualifiedName = _computeQualifiedName(owner, simpleName);
- }
- return _qualifiedName;
- }
-
- var _owner;
- DeclarationMirror get owner {
- if (_owner is! Mirror) {
- _owner = _owner.resolve(mirrors);
- }
- return _owner;
- }
+ final DeclarationMirror owner;
bool get isPrivate {
return _n(simpleName).startsWith('_');
@@ -1089,14 +1003,11 @@
'VariableMirror.location is not implemented');
}
- var _type;
+ TypeMirror _type;
TypeMirror get type {
if (_type == null) {
_type = _VariableMirror_type(_reflectee);
}
- if (_type is! Mirror) {
- _type = _type.resolve(mirrors);
- }
return _type;
}
@@ -1174,7 +1085,7 @@
// TODO(11955): Remove once dynamicType and voidType are canonical objects in
// the object store.
- operator ==(other) {
+ bool operator ==(other) {
if (other is! _SpecialTypeMirrorImpl) {
return false;
}
@@ -1217,13 +1128,11 @@
}
}
- // Creates a new local InstanceMirror
- static InstanceMirror makeLocalInstanceMirror(Object reflectee)
- native 'Mirrors_makeLocalInstanceMirror';
-
// Creates a new local mirror for some Object.
static InstanceMirror reflect(Object reflectee) {
- return makeLocalInstanceMirror(reflectee);
+ return reflectee is Function
+ ? new _LocalClosureMirrorImpl(reflectee)
+ : new _LocalInstanceMirrorImpl(reflectee);
}
// Creates a new local ClassMirror.
diff --git a/runtime/lib/object.cc b/runtime/lib/object.cc
index 8410af4..086198a 100644
--- a/runtime/lib/object.cc
+++ b/runtime/lib/object.cc
@@ -115,6 +115,17 @@
const bool is_instance_of = instance.IsInstanceOf(type,
instantiator_type_arguments,
&malformed_error);
+ if (FLAG_trace_type_checks) {
+ const char* result_str = is_instance_of ? "true" : "false";
+ OS::Print("Object.instanceOf: result %s\n", result_str);
+ const Type& instance_type = Type::Handle(instance.GetType());
+ OS::Print(" instance type: %s\n",
+ String::Handle(instance_type.Name()).ToCString());
+ OS::Print(" test type: %s\n", String::Handle(type.Name()).ToCString());
+ if (!malformed_error.IsNull()) {
+ OS::Print(" malformed error: %s\n", malformed_error.ToErrorCString());
+ }
+ }
if (!is_instance_of && !malformed_error.IsNull()) {
// Throw a dynamic type error only if the instanceof test fails.
DartFrameIterator iterator;
@@ -128,17 +139,6 @@
Symbols::Empty(), malformed_error_message);
UNREACHABLE();
}
-
- if (FLAG_trace_type_checks) {
- const char* result_str = is_instance_of ? "true" : "false";
- OS::Print("Object.instanceOf: result %s\n", result_str);
- const Class& instance_class = Class::Handle(instance.clazz());
- OS::Print(" instance [class: %s]\n",
- String::Handle(instance_class.Name()).ToCString());
- OS::Print(" test-type [class: %s]\n",
- String::Handle(Class::Handle(type.type_class()).Name()).ToCString());
- OS::Print(" type-args %s\n", instantiator_type_arguments.ToCString());
- }
return Bool::Get(negate.value() ? !is_instance_of : is_instance_of);
}
diff --git a/runtime/lib/typed_data.dart b/runtime/lib/typed_data.dart
index 437be6a..de61ae0 100644
--- a/runtime/lib/typed_data.dart
+++ b/runtime/lib/typed_data.dart
@@ -229,6 +229,14 @@
return new _Float32x4Array(length);
}
+ /* patch */ factory Float32x4List.fromList(List<Float32x4> elements) {
+ var result = new _Float32x4Array(elements.length);
+ for (int i = 0; i < elements.length; i++) {
+ result[i] = elements[i];
+ }
+ return result;
+ }
+
/* patch */ factory Float32x4List.view(ByteBuffer buffer,
[int offsetInBytes = 0, int length]) {
return new _Float32x4ArrayView(buffer, offsetInBytes, length);
diff --git a/runtime/tests/vm/dart/isolate_mirror_local_test.dart b/runtime/tests/vm/dart/isolate_mirror_local_test.dart
index dc31e38..b07be27 100644
--- a/runtime/tests/vm/dart/isolate_mirror_local_test.dart
+++ b/runtime/tests/vm/dart/isolate_mirror_local_test.dart
@@ -390,8 +390,7 @@
}
void testNullInstanceMirror(InstanceMirror mirror) {
- // TODO(turnidge): This is returning the wrong class. Fix it.
- Expect.equals(const Symbol('Object'), mirror.type.simpleName);
+ Expect.equals(const Symbol('Null'), mirror.type.simpleName);
Expect.isTrue(mirror.hasReflectee);
Expect.equals(null, mirror.reflectee);
Expect.equals("InstanceMirror on null", mirror.toString());
diff --git a/runtime/vm/assembler.cc b/runtime/vm/assembler.cc
index 64a7716..dc33ed5 100644
--- a/runtime/vm/assembler.cc
+++ b/runtime/vm/assembler.cc
@@ -15,6 +15,11 @@
DEFINE_FLAG(bool, code_comments, false,
"Include comments into code and disassembly");
+// TODO(zra): Remove once far branches are enabled automatically on a
+// per-function basis.
+#if defined(TARGET_ARCH_ARM) || defined(TARGET_ARCH_MIPS)
+DEFINE_FLAG(bool, use_far_branches, false, "Enable far branches");
+#endif
static uword NewContents(intptr_t capacity) {
diff --git a/runtime/vm/assembler.h b/runtime/vm/assembler.h
index 200716a..102afc8 100644
--- a/runtime/vm/assembler.h
+++ b/runtime/vm/assembler.h
@@ -13,6 +13,12 @@
namespace dart {
+// TODO(zra): Remove once far branches are enabled automatically on a
+// per-function basis.
+#if defined(TARGET_ARCH_ARM) || defined(TARGET_ARCH_MIPS)
+DECLARE_FLAG(bool, use_far_branches);
+#endif
+
// Forward declarations.
class Assembler;
class AssemblerFixup;
diff --git a/runtime/vm/assembler_arm.cc b/runtime/vm/assembler_arm.cc
index e50ac3a..d08f3db 100644
--- a/runtime/vm/assembler_arm.cc
+++ b/runtime/vm/assembler_arm.cc
@@ -305,18 +305,6 @@
}
-void Assembler::EmitBranch(Condition cond, Label* label, bool link) {
- if (label->IsBound()) {
- EmitType5(cond, label->Position() - buffer_.Size(), link);
- } else {
- int position = buffer_.Size();
- // Use the offset field of the branch instruction for linking the sites.
- EmitType5(cond, label->position_, link);
- label->LinkTo(position);
- }
-}
-
-
void Assembler::and_(Register rd, Register rn, ShifterOperand so,
Condition cond) {
EmitType01(cond, so.type(), AND, 0, rn, rd, so);
@@ -1424,6 +1412,11 @@
}
+void Assembler::vzipqw(QRegister qd, QRegister qm) {
+ EmitSIMDqqq(B24 | B23 | B21 | B20 | B19 | B17 | B8 | B7, kByte, qd, Q0, qm);
+}
+
+
void Assembler::vceqqi(OperandSize sz,
QRegister qd, QRegister qn, QRegister qm) {
EmitSIMDqqq(B24 | B11 | B4, sz, qd, qn, qm);
@@ -1725,15 +1718,172 @@
}
+static bool CanEncodeBranchOffset(int32_t offset) {
+ offset -= Instr::kPCReadOffset;
+ ASSERT(Utils::IsAligned(offset, 4));
+ return Utils::IsInt(Utils::CountOneBits(kBranchOffsetMask), offset);
+}
+
+
+int32_t Assembler::EncodeBranchOffset(int32_t offset, int32_t inst) {
+ // The offset is off by 8 due to the way the ARM CPUs read PC.
+ offset -= Instr::kPCReadOffset;
+ ASSERT(Utils::IsAligned(offset, 4));
+ ASSERT(Utils::IsInt(Utils::CountOneBits(kBranchOffsetMask), offset));
+
+ // Properly preserve only the bits supported in the instruction.
+ offset >>= 2;
+ offset &= kBranchOffsetMask;
+ return (inst & ~kBranchOffsetMask) | offset;
+}
+
+
+int Assembler::DecodeBranchOffset(int32_t inst) {
+ // Sign-extend, left-shift by 2, then add 8.
+ return ((((inst & kBranchOffsetMask) << 8) >> 6) + Instr::kPCReadOffset);
+}
+
+
+static int32_t DecodeLoadImmediate(int32_t movt, int32_t movw) {
+ int32_t offset = 0;
+ offset |= (movt & 0xf0000) << 12;
+ offset |= (movt & 0xfff) << 16;
+ offset |= (movw & 0xf0000) >> 4;
+ offset |= movw & 0xfff;
+ return offset;
+}
+
+
+class PatchFarBranch : public AssemblerFixup {
+ public:
+ PatchFarBranch() {}
+
+ void Process(const MemoryRegion& region, int position) {
+ const int32_t movw = region.Load<int32_t>(position);
+ const int32_t movt = region.Load<int32_t>(position + Instr::kInstrSize);
+ const int32_t bx = region.Load<int32_t>(position + 2 * Instr::kInstrSize);
+
+ if (((movt & 0xfff0f000) == 0xe340c000) && // movt IP, high
+ ((movw & 0xfff0f000) == 0xe300c000)) { // movw IP, low
+ const int32_t offset = DecodeLoadImmediate(movt, movw);
+ const int32_t dest = region.start() + offset;
+ const uint16_t dest_high = Utils::High16Bits(dest);
+ const uint16_t dest_low = Utils::Low16Bits(dest);
+ const int32_t patched_movt =
+ 0xe340c000 | ((dest_high >> 12) << 16) | (dest_high & 0xfff);
+ const int32_t patched_movw =
+ 0xe300c000 | ((dest_low >> 12) << 16) | (dest_low & 0xfff);
+
+ region.Store<int32_t>(position, patched_movw);
+ region.Store<int32_t>(position + Instr::kInstrSize, patched_movt);
+ return;
+ }
+
+ // If the offset loading instructions aren't there, we must have replaced
+ // the far branch with a near one, and so these instructions should be NOPs.
+ ASSERT((movt == Instr::kNopInstruction) &&
+ (bx == Instr::kNopInstruction));
+ }
+};
+
+
+void Assembler::EmitFarBranch(Condition cond, int32_t offset, bool link) {
+ const uint16_t low = Utils::Low16Bits(offset);
+ const uint16_t high = Utils::High16Bits(offset);
+ buffer_.EmitFixup(new PatchFarBranch());
+ movw(IP, low);
+ movt(IP, high);
+ if (link) {
+ blx(IP, cond);
+ } else {
+ bx(IP, cond);
+ }
+}
+
+
+void Assembler::EmitBranch(Condition cond, Label* label, bool link) {
+ if (label->IsBound()) {
+ const int32_t dest = label->Position() - buffer_.Size();
+ if (FLAG_use_far_branches && !CanEncodeBranchOffset(dest)) {
+ EmitFarBranch(cond, label->Position(), link);
+ } else {
+ EmitType5(cond, dest, link);
+ }
+ } else {
+ const int position = buffer_.Size();
+ if (FLAG_use_far_branches) {
+ const int32_t dest = label->position_;
+ EmitFarBranch(cond, dest, link);
+ } else {
+ // Use the offset field of the branch instruction for linking the sites.
+ EmitType5(cond, label->position_, link);
+ }
+ label->LinkTo(position);
+ }
+}
+
+
void Assembler::Bind(Label* label) {
ASSERT(!label->IsBound());
int bound_pc = buffer_.Size();
while (label->IsLinked()) {
- int32_t position = label->Position();
- int32_t next = buffer_.Load<int32_t>(position);
- int32_t encoded = Assembler::EncodeBranchOffset(bound_pc - position, next);
- buffer_.Store<int32_t>(position, encoded);
- label->position_ = Assembler::DecodeBranchOffset(next);
+ const int32_t position = label->Position();
+ int32_t dest = bound_pc - position;
+ if (FLAG_use_far_branches && !CanEncodeBranchOffset(dest)) {
+ // Far branches are enabled and we can't encode the branch offset.
+
+ // Grab instructions that load the offset.
+ const int32_t movw =
+ buffer_.Load<int32_t>(position);
+ const int32_t movt =
+ buffer_.Load<int32_t>(position + 1 * Instr::kInstrSize);
+
+ // Change from relative to the branch to relative to the assembler buffer.
+ dest = buffer_.Size();
+ const uint16_t dest_high = Utils::High16Bits(dest);
+ const uint16_t dest_low = Utils::Low16Bits(dest);
+ const int32_t patched_movt =
+ 0xe340c000 | ((dest_high >> 12) << 16) | (dest_high & 0xfff);
+ const int32_t patched_movw =
+ 0xe300c000 | ((dest_low >> 12) << 16) | (dest_low & 0xfff);
+
+ // Rewrite the instructions.
+ buffer_.Store<int32_t>(position, patched_movw);
+ buffer_.Store<int32_t>(position + 1 * Instr::kInstrSize, patched_movt);
+ label->position_ = DecodeLoadImmediate(movt, movw);
+ } else if (FLAG_use_far_branches && CanEncodeBranchOffset(dest)) {
+ // Far branches are enabled, but we can encode the branch offset.
+
+ // Grab instructions that load the offset, and the branch.
+ const int32_t movw =
+ buffer_.Load<int32_t>(position);
+ const int32_t movt =
+ buffer_.Load<int32_t>(position + 1 * Instr::kInstrSize);
+ const int32_t branch =
+ buffer_.Load<int32_t>(position + 2 * Instr::kInstrSize);
+
+ // Grab the branch condition, and encode the link bit.
+ const int32_t cond = branch & 0xf0000000;
+ const int32_t link = (branch & 0x20) << 19;
+
+ // Encode the branch and the offset.
+ const int32_t new_branch = cond | link | 0x0a000000;
+ const int32_t encoded = EncodeBranchOffset(dest, new_branch);
+
+ // Write the encoded branch instruction followed by two nops.
+ buffer_.Store<int32_t>(position, encoded);
+ buffer_.Store<int32_t>(position + 1 * Instr::kInstrSize,
+ Instr::kNopInstruction);
+ buffer_.Store<int32_t>(position + 2 * Instr::kInstrSize,
+ Instr::kNopInstruction);
+
+ label->position_ = DecodeLoadImmediate(movt, movw);
+ } else {
+ int32_t next = buffer_.Load<int32_t>(position);
+ int32_t encoded = Assembler::EncodeBranchOffset(dest, next);
+ buffer_.Store<int32_t>(position, encoded);
+ label->position_ = Assembler::DecodeBranchOffset(next);
+ }
}
label->BindTo(bound_pc);
}
@@ -2415,10 +2565,10 @@
const intptr_t offset = CodeSize();
Comment("EnterOsrFrame");
- mov(TMP, ShifterOperand(PC));
+ mov(IP, ShifterOperand(PC));
- AddImmediate(TMP, -offset);
- str(TMP, Address(FP, kPcMarkerSlotFromFp * kWordSize));
+ AddImmediate(IP, -offset);
+ str(IP, Address(FP, kPcMarkerSlotFromFp * kWordSize));
// Setup pool pointer for this dart function.
LoadPoolPointer();
@@ -2473,16 +2623,16 @@
AddImmediate(instance_reg, instance_size);
// instance_reg: potential next object start.
- LoadImmediate(TMP, heap->EndAddress());
- ldr(TMP, Address(TMP, 0));
- cmp(TMP, ShifterOperand(instance_reg));
+ LoadImmediate(IP, heap->EndAddress());
+ ldr(IP, Address(IP, 0));
+ cmp(IP, ShifterOperand(instance_reg));
// fail if heap end unsigned less than or equal to instance_reg.
b(failure, LS);
// Successfully allocated the object, now update top to point to
// next object start and store the class in the class field of object.
- LoadImmediate(TMP, heap->TopAddress());
- str(instance_reg, Address(TMP, 0));
+ LoadImmediate(IP, heap->TopAddress());
+ str(instance_reg, Address(IP, 0));
ASSERT(instance_size >= kHeapObjectTag);
AddImmediate(instance_reg, -instance_size + kHeapObjectTag);
@@ -2491,8 +2641,8 @@
tags = RawObject::SizeTag::update(instance_size, tags);
ASSERT(cls.id() != kIllegalCid);
tags = RawObject::ClassIdTag::update(cls.id(), tags);
- LoadImmediate(TMP, tags);
- str(TMP, FieldAddress(instance_reg, Object::tags_offset()));
+ LoadImmediate(IP, tags);
+ str(IP, FieldAddress(instance_reg, Object::tags_offset()));
} else {
b(failure);
}
@@ -2518,25 +2668,6 @@
}
-int32_t Assembler::EncodeBranchOffset(int32_t offset, int32_t inst) {
- // The offset is off by 8 due to the way the ARM CPUs read PC.
- offset -= 8;
- ASSERT(Utils::IsAligned(offset, 4));
- ASSERT(Utils::IsInt(Utils::CountOneBits(kBranchOffsetMask), offset));
-
- // Properly preserve only the bits supported in the instruction.
- offset >>= 2;
- offset &= kBranchOffsetMask;
- return (inst & ~kBranchOffsetMask) | offset;
-}
-
-
-int Assembler::DecodeBranchOffset(int32_t inst) {
- // Sign-extend, left-shift by 2, then add 8.
- return ((((inst & kBranchOffsetMask) << 8) >> 6) + 8);
-}
-
-
int32_t Assembler::AddObject(const Object& obj) {
ASSERT(obj.IsNotTemporaryScopedHandle());
ASSERT(obj.IsOld());
diff --git a/runtime/vm/assembler_arm.h b/runtime/vm/assembler_arm.h
index 5044eed..d9cb891 100644
--- a/runtime/vm/assembler_arm.h
+++ b/runtime/vm/assembler_arm.h
@@ -538,6 +538,10 @@
// a list of 'length' registers starting with dn. The result is placed in dd.
void vtbl(DRegister dd, DRegister dn, int length, DRegister dm);
+ // The words of qd and qm are interleaved with the low words of the result
+ // in qd and the high words in qm.
+ void vzipqw(QRegister qd, QRegister qm);
+
// Branch instructions.
void b(Label* label, Condition cond = AL);
void bl(Label* label, Condition cond = AL);
@@ -843,6 +847,7 @@
void EmitSIMDddd(int32_t opcode, OperandSize sz,
DRegister dd, DRegister dn, DRegister dm);
+ void EmitFarBranch(Condition cond, int32_t offset, bool link);
void EmitBranch(Condition cond, Label* label, bool link);
static int32_t EncodeBranchOffset(int32_t offset, int32_t inst);
static int DecodeBranchOffset(int32_t inst);
diff --git a/runtime/vm/assembler_arm_test.cc b/runtime/vm/assembler_arm_test.cc
index 3e61347..47f656c 100644
--- a/runtime/vm/assembler_arm_test.cc
+++ b/runtime/vm/assembler_arm_test.cc
@@ -2638,6 +2638,40 @@
}
+ASSEMBLER_TEST_GENERATE(Vzipqw, assembler) {
+ if (CPUFeatures::neon_supported()) {
+ __ LoadSImmediate(S0, 0.0);
+ __ LoadSImmediate(S1, 1.0);
+ __ LoadSImmediate(S2, 2.0);
+ __ LoadSImmediate(S3, 3.0);
+ __ LoadSImmediate(S4, 4.0);
+ __ LoadSImmediate(S5, 5.0);
+ __ LoadSImmediate(S6, 6.0);
+ __ LoadSImmediate(S7, 7.0);
+
+ __ vzipqw(Q0, Q1);
+
+ __ vsubqs(Q0, Q1, Q0);
+
+ __ vadds(S0, S0, S1);
+ __ vadds(S0, S0, S2);
+ __ vadds(S0, S0, S3);
+ __ bx(LR);
+ } else {
+ __ LoadSImmediate(S0, 8.0);
+ __ bx(LR);
+ }
+}
+
+
+ASSEMBLER_TEST_RUN(Vzipqw, test) {
+ EXPECT(test != NULL);
+ typedef float (*Vzipqw)();
+ float res = EXECUTE_TEST_CODE_FLOAT(Vzipqw, test->entry());
+ EXPECT_FLOAT_EQ(8.0, res, 0.0001f);
+}
+
+
ASSEMBLER_TEST_GENERATE(Vceqqi32, assembler) {
if (CPUFeatures::neon_supported()) {
__ mov(R0, ShifterOperand(1));
diff --git a/runtime/vm/assembler_ia32.cc b/runtime/vm/assembler_ia32.cc
index 4244adb..c04347c 100644
--- a/runtime/vm/assembler_ia32.cc
+++ b/runtime/vm/assembler_ia32.cc
@@ -330,6 +330,22 @@
}
+void Assembler::cmovgel(Register dst, Register src) {
+ AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+ EmitUint8(0x0F);
+ EmitUint8(0x4D);
+ EmitRegisterOperand(dst, src);
+}
+
+
+void Assembler::cmovlessl(Register dst, Register src) {
+ AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+ EmitUint8(0x0F);
+ EmitUint8(0x4C);
+ EmitRegisterOperand(dst, src);
+}
+
+
void Assembler::rep_movsb() {
AssemblerBuffer::EnsureCapacity ensured(&buffer_);
EmitUint8(0xF3);
diff --git a/runtime/vm/assembler_ia32.h b/runtime/vm/assembler_ia32.h
index b9aa149..3103b5d 100644
--- a/runtime/vm/assembler_ia32.h
+++ b/runtime/vm/assembler_ia32.h
@@ -366,6 +366,9 @@
void cmovs(Register dst, Register src);
void cmovns(Register dst, Register src);
+ void cmovgel(Register dst, Register src);
+ void cmovlessl(Register dst, Register src);
+
void rep_movsb();
void movss(XmmRegister dst, const Address& src);
diff --git a/runtime/vm/assembler_ia32_test.cc b/runtime/vm/assembler_ia32_test.cc
index edb1820..3a7d4a5 100644
--- a/runtime/vm/assembler_ia32_test.cc
+++ b/runtime/vm/assembler_ia32_test.cc
@@ -2627,6 +2627,28 @@
}
+ASSEMBLER_TEST_GENERATE(ConditionalMovesCompare, assembler) {
+ __ movl(EDX, Immediate(1)); // Greater equal.
+ __ movl(ECX, Immediate(-1)); // Less
+ __ movl(EAX, Address(ESP, 1 * kWordSize));
+ __ cmpl(EAX, Address(ESP, 2 * kWordSize));
+ __ cmovlessl(EAX, ECX);
+ __ cmovgel(EAX, EDX);
+ __ ret();
+}
+
+
+ASSEMBLER_TEST_RUN(ConditionalMovesCompare, test) {
+ typedef int (*ConditionalMovesCompareCode)(int i, int j);
+ int res = reinterpret_cast<ConditionalMovesCompareCode>(test->entry())(10, 5);
+ EXPECT_EQ(1, res); // Greater equal.
+ res = reinterpret_cast<ConditionalMovesCompareCode>(test->entry())(5, 5);
+ EXPECT_EQ(1, res); // Greater equal.
+ res = reinterpret_cast<ConditionalMovesCompareCode>(test->entry())(2, 5);
+ EXPECT_EQ(-1, res); // Less.
+}
+
+
ASSEMBLER_TEST_GENERATE(TestLoadDoubleConstant, assembler) {
__ LoadDoubleConstant(XMM3, -12.34);
__ pushl(EAX);
diff --git a/runtime/vm/assembler_mips.cc b/runtime/vm/assembler_mips.cc
index f1f15e0..47b423f 100644
--- a/runtime/vm/assembler_mips.cc
+++ b/runtime/vm/assembler_mips.cc
@@ -17,7 +17,6 @@
DECLARE_FLAG(bool, trace_sim);
#endif
DEFINE_FLAG(bool, print_stop_message, false, "Print stop message.");
-DEFINE_FLAG(bool, use_far_branches, false, "Enable far branches on MIPS");
DECLARE_FLAG(bool, inline_alloc);
void Assembler::InitializeMemoryWithBreakpoints(uword data, int length) {
diff --git a/runtime/vm/assembler_mips.h b/runtime/vm/assembler_mips.h
index d2cb44f..2d45ef7 100644
--- a/runtime/vm/assembler_mips.h
+++ b/runtime/vm/assembler_mips.h
@@ -22,8 +22,6 @@
// The MIPS32® Instruction Set" in short "VolII-A"
namespace dart {
-DECLARE_FLAG(bool, use_far_branches);
-
// Forward declarations.
class RuntimeEntry;
diff --git a/runtime/vm/assembler_x64.cc b/runtime/vm/assembler_x64.cc
index ebeb998..488cd55 100644
--- a/runtime/vm/assembler_x64.cc
+++ b/runtime/vm/assembler_x64.cc
@@ -406,6 +406,27 @@
}
+void Assembler::cmovgeq(Register dst, Register src) {
+ AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+ Operand operand(src);
+ EmitOperandREX(dst, operand, REX_W);
+ EmitUint8(0x0F);
+ EmitUint8(0x4D);
+ EmitOperand(dst & 7, operand);
+}
+
+
+void Assembler::cmovlessq(Register dst, Register src) {
+ AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+ Operand operand(src);
+ EmitOperandREX(dst, operand, REX_W);
+ EmitUint8(0x0F);
+ EmitUint8(0x4C);
+ EmitOperand(dst & 7, operand);
+}
+
+
+
void Assembler::movss(XmmRegister dst, const Address& src) {
ASSERT(dst <= XMM15);
AssemblerBuffer::EnsureCapacity ensured(&buffer_);
diff --git a/runtime/vm/assembler_x64.h b/runtime/vm/assembler_x64.h
index c87aec7..165642b 100644
--- a/runtime/vm/assembler_x64.h
+++ b/runtime/vm/assembler_x64.h
@@ -383,6 +383,9 @@
void leaq(Register dst, const Address& src);
+ void cmovgeq(Register dst, Register src);
+ void cmovlessq(Register dst, Register src);
+
void movss(XmmRegister dst, const Address& src);
void movss(const Address& dst, XmmRegister src);
void movss(XmmRegister dst, XmmRegister src);
diff --git a/runtime/vm/assembler_x64_test.cc b/runtime/vm/assembler_x64_test.cc
index 688f874..7fe6a08 100644
--- a/runtime/vm/assembler_x64_test.cc
+++ b/runtime/vm/assembler_x64_test.cc
@@ -2567,6 +2567,29 @@
delete [] to;
}
+
+ASSEMBLER_TEST_GENERATE(ConditionalMovesCompare, assembler) {
+ // RDI: Arg0.
+ // RSI: Arg1.
+ __ movq(RDX, Immediate(1)); // Greater equal.
+ __ movq(RCX, Immediate(-1)); // Less
+ __ cmpq(RDI, RSI);
+ __ cmovlessq(RAX, RCX);
+ __ cmovgeq(RAX, RDX);
+ __ ret();
+}
+
+
+ASSEMBLER_TEST_RUN(ConditionalMovesCompare, test) {
+ typedef int (*ConditionalMovesCompareCode)(int i, int j);
+ int res = reinterpret_cast<ConditionalMovesCompareCode>(test->entry())(10, 5);
+ EXPECT_EQ(1, res); // Greater equal.
+ res = reinterpret_cast<ConditionalMovesCompareCode>(test->entry())(5, 5);
+ EXPECT_EQ(1, res); // Greater equal.
+ res = reinterpret_cast<ConditionalMovesCompareCode>(test->entry())(2, 5);
+ EXPECT_EQ(-1, res); // Less.
+}
+
} // namespace dart
#endif // defined TARGET_ARCH_X64
diff --git a/runtime/vm/bootstrap_natives.h b/runtime/vm/bootstrap_natives.h
index 26d8be4..d890bf4 100644
--- a/runtime/vm/bootstrap_natives.h
+++ b/runtime/vm/bootstrap_natives.h
@@ -240,16 +240,18 @@
V(isolate_spawnFunction, 2) \
V(isolate_spawnUri, 1) \
V(Mirrors_isLocalPort, 1) \
- V(Mirrors_makeLocalInstanceMirror, 1) \
V(Mirrors_makeLocalClassMirror, 1) \
V(Mirrors_makeLocalMirrorSystem, 0) \
+ V(MirrorReference_equals, 2) \
V(InstanceMirror_invoke, 4) \
V(InstanceMirror_invokeGetter, 3) \
V(InstanceMirror_invokeSetter, 4) \
+ V(ClosureMirror_function, 1) \
V(ClosureMirror_apply, 2) \
V(ClassMirror_name, 1) \
V(ClassMirror_library, 1) \
V(ClassMirror_supertype, 1) \
+ V(ClassMirror_interfaces, 1) \
V(ClassMirror_members, 2) \
V(ClassMirror_constructors, 2) \
V(LibraryMirror_members, 2) \
@@ -257,15 +259,20 @@
V(ClassMirror_invokeGetter, 3) \
V(ClassMirror_invokeSetter, 4) \
V(ClassMirror_invokeConstructor, 3) \
+ V(ClassMirror_type_variables, 1) \
V(LibraryMirror_invoke, 4) \
V(LibraryMirror_invokeGetter, 3) \
V(LibraryMirror_invokeSetter, 4) \
+ V(LocalTypeVariableMirror_owner, 1) \
+ V(LocalTypeVariableMirror_upper_bound, 1) \
V(DeclarationMirror_metadata, 1) \
- V(MethodMirror_name, 1) \
+ V(FunctionTypeMirror_parameters, 1) \
+ V(FunctionTypeMirror_return_type, 1) \
V(MethodMirror_owner, 1) \
V(MethodMirror_parameters, 1) \
V(MethodMirror_return_type, 1) \
V(ParameterMirror_type, 2) \
+ V(TypedefMirror_referent, 1) \
V(VariableMirror_type, 1) \
V(GrowableObjectArray_allocate, 2) \
V(GrowableObjectArray_getIndexed, 2) \
diff --git a/runtime/vm/class_finalizer.cc b/runtime/vm/class_finalizer.cc
index 0134612..91410fa 100644
--- a/runtime/vm/class_finalizer.cc
+++ b/runtime/vm/class_finalizer.cc
@@ -347,7 +347,6 @@
Error::Handle(), // No previous error.
cls,
factory.token_pos(),
- kResolveTypeParameters, // No compile-time error.
"factory may not redirect to 'dynamic'");
factory.SetRedirectionType(type);
ASSERT(factory.RedirectionTarget() == Function::null());
@@ -375,7 +374,6 @@
Error::Handle(), // No previous error.
cls,
factory.token_pos(),
- kResolveTypeParameters, // No compile-time error.
"class '%s' has no constructor or factory named '%s'",
target_class_name.ToCString(),
user_visible_target_name.ToCString());
@@ -390,7 +388,6 @@
Error::Handle(), // No previous error.
cls,
factory.token_pos(),
- kResolveTypeParameters, // No compile-time error.
"constructor '%s' has incompatible parameters with "
"redirecting factory '%s'",
String::Handle(target.name()).ToCString(),
@@ -437,8 +434,7 @@
if (malformed_error.IsNull()) {
target_type ^= FinalizeType(cls, target_type, kCanonicalize);
} else {
- FinalizeMalformedType(malformed_error,
- cls, target_type, kFinalize,
+ FinalizeMalformedType(malformed_error, cls, target_type,
"cannot resolve redirecting factory");
target_target = Function::null();
}
@@ -453,9 +449,6 @@
const AbstractType& type,
FinalizationKind finalization) {
if (type.IsResolved() || type.IsFinalized()) {
- if ((finalization == kCanonicalizeWellFormed) && type.IsMalformed()) {
- ReportError(Error::Handle(type.malformed_error()));
- }
return;
}
if (FLAG_trace_type_finalization) {
@@ -479,17 +472,27 @@
// Replace unresolved class with resolved type class.
const Type& parameterized_type = Type::Cast(type);
- if (!type_class.IsNull()) {
- parameterized_type.set_type_class(type_class);
- } else {
- // The type class could not be resolved. The type is malformed.
- FinalizeMalformedType(ambiguous_error, // May be null.
- cls, parameterized_type, finalization,
- "cannot resolve class name '%s' from '%s'",
- String::Handle(unresolved_class.Name()).ToCString(),
- String::Handle(cls.Name()).ToCString());
+ if (type_class.IsNull()) {
+ if ((finalization == kCanonicalizeWellFormed) ||
+ FLAG_error_on_malformed_type) {
+ // The type class could not be resolved. The type is malformed.
+ FinalizeMalformedType(
+ ambiguous_error, // May be null.
+ cls,
+ parameterized_type,
+ "cannot resolve class '%s' from '%s'",
+ String::Handle(unresolved_class.Name()).ToCString(),
+ String::Handle(cls.Name()).ToCString());
+ } else {
+ // Map the malformed type to dynamic and ignore type arguments.
+ parameterized_type.set_type_class(Class::Handle(
+ Object::dynamic_class()));
+ parameterized_type.set_arguments(
+ Object::null_abstract_type_arguments());
+ }
return;
}
+ parameterized_type.set_type_class(type_class);
}
// Resolve type arguments, if any.
@@ -708,14 +711,8 @@
if (type.IsFinalized()) {
// Ensure type is canonical if canonicalization is requested, unless type is
// malformed.
- if (finalization >= kCanonicalize) {
- if (type.IsMalformed()) {
- if (finalization == kCanonicalizeWellFormed) {
- ReportError(Error::Handle(type.malformed_error()));
- }
- } else {
- return type.Canonicalize();
- }
+ if ((finalization >= kCanonicalize) && !type.IsMalformed()) {
+ return type.Canonicalize();
}
return type.raw();
}
@@ -749,15 +746,8 @@
// At this point, we can only have a parameterized_type.
const Type& parameterized_type = Type::Cast(type);
- if (parameterized_type.IsBeingFinalized()) {
- // Self reference detected. The type is malformed.
- FinalizeMalformedType(
- Error::Handle(), // No previous error.
- cls, parameterized_type, finalization,
- "type '%s' illegally refers to itself",
- String::Handle(parameterized_type.UserVisibleName()).ToCString());
- return parameterized_type.raw();
- }
+ // Types illegally referring to themselves should have been detected earlier.
+ ASSERT(!parameterized_type.IsBeingFinalized());
// Mark type as being finalized in order to detect illegal self reference.
parameterized_type.set_is_being_finalized();
@@ -784,19 +774,8 @@
type_argument = arguments.TypeAt(i);
type_argument = FinalizeType(cls, type_argument, finalization);
if (type_argument.IsMalformed()) {
- // In production mode, malformed type arguments are mapped to dynamic.
- // In checked mode, a type with malformed type arguments is malformed.
- if (FLAG_enable_type_checks || FLAG_error_on_malformed_type) {
- const Error& error = Error::Handle(type_argument.malformed_error());
- const String& type_name =
- String::Handle(parameterized_type.UserVisibleName());
- FinalizeMalformedType(error, cls, parameterized_type, finalization,
- "type '%s' has malformed type argument",
- type_name.ToCString());
- return parameterized_type.raw();
- } else {
- type_argument = Type::DynamicType();
- }
+ // Malformed type arguments are mapped to dynamic.
+ type_argument = Type::DynamicType();
}
arguments.SetTypeAt(i, type_argument);
}
@@ -813,20 +792,17 @@
// However, type parameter bounds are checked below, even for a raw type.
if (!arguments.IsNull() && (arguments.Length() != num_type_parameters)) {
// Wrong number of type arguments. The type is malformed.
- if (finalization >= kCanonicalizeExpression) {
+ if (FLAG_error_on_malformed_type) {
const Script& script = Script::Handle(cls.script());
- const String& type_name =
- String::Handle(parameterized_type.UserVisibleName());
+ const String& type_class_name = String::Handle(type_class.Name());
ReportError(script, parameterized_type.token_pos(),
- "wrong number of type arguments in type '%s'",
- type_name.ToCString());
+ "wrong number of type arguments for class '%s'",
+ type_class_name.ToCString());
}
- FinalizeMalformedType(
- Error::Handle(), // No previous error.
- cls, parameterized_type, finalization,
- "wrong number of type arguments in type '%s'",
- String::Handle(parameterized_type.UserVisibleName()).ToCString());
- return parameterized_type.raw();
+ // Make the type raw and continue without reporting any error.
+ // A static warning should have been reported.
+ arguments = AbstractTypeArguments::null();
+ parameterized_type.set_arguments(arguments);
}
// The full type argument vector consists of the type arguments of the
// super types of type_class, which may be initialized from the parsed
@@ -908,17 +884,12 @@
// The malformed bound will be ignored in production mode.
if (!bound_error.IsNull()) {
// No compile-time error during finalization.
- FinalizationKind bound_finalization = kResolveTypeParameters;
- if (FLAG_enable_type_checks || FLAG_error_on_malformed_type) {
- bound_finalization = finalization;
- }
const String& parameterized_type_name = String::Handle(
parameterized_type.UserVisibleName());
const Type& malformed_bound = Type::Handle(
NewFinalizedMalformedType(bound_error,
cls,
parameterized_type.token_pos(),
- bound_finalization,
"type '%s' has an out of bound type argument",
parameterized_type_name.ToCString()));
return BoundedType::New(parameterized_type,
@@ -942,10 +913,8 @@
// interface.
ResolveType(cls, type, kCanonicalize);
type = FinalizeType(cls, type, kCanonicalize);
- // In production mode, a malformed result type is mapped to dynamic.
- if (!FLAG_enable_type_checks && type.IsMalformed()) {
- type = Type::DynamicType();
- }
+ // A malformed result type is mapped to dynamic.
+ ASSERT(!type.IsMalformed());
function.set_result_type(type);
// Resolve formal parameter types.
const intptr_t num_parameters = function.NumParameters();
@@ -953,10 +922,8 @@
type = function.ParameterTypeAt(i);
ResolveType(cls, type, kCanonicalize);
type = FinalizeType(cls, type, kCanonicalize);
- // In production mode, a malformed parameter type is mapped to dynamic.
- if (!FLAG_enable_type_checks && type.IsMalformed()) {
- type = Type::DynamicType();
- }
+ // A malformed parameter type is mapped to dynamic.
+ ASSERT(!type.IsMalformed());
function.SetParameterTypeAt(i, type);
}
}
@@ -1875,6 +1842,9 @@
// Resolve super type. Failures lead to a longjmp.
ResolveType(cls, super_type, kCanonicalizeWellFormed);
+ if (super_type.IsMalformed()) {
+ ReportError(Error::Handle(super_type.malformed_error()));
+ }
if (super_type.IsDynamicType()) {
const Script& script = Script::Handle(cls.script());
ReportError(script, cls.token_pos(),
@@ -1940,6 +1910,9 @@
interface ^= super_interfaces.At(i);
ResolveType(cls, interface, kCanonicalizeWellFormed);
ASSERT(!interface.IsTypeParameter()); // Should be detected by parser.
+ if (interface.IsMalformed()) {
+ ReportError(Error::Handle(interface.malformed_error()));
+ }
if (interface.IsDynamicType()) {
const Script& script = Script::Handle(cls.script());
ReportError(script, cls.token_pos(),
@@ -2051,35 +2024,24 @@
void ClassFinalizer::ReportMalformedType(const Error& prev_error,
const Class& cls,
const Type& type,
- FinalizationKind finalization,
const char* format,
va_list args) {
LanguageError& error = LanguageError::Handle();
- if (FLAG_enable_type_checks ||
- !type.HasResolvedTypeClass() ||
- (finalization == kCanonicalizeWellFormed) ||
- FLAG_error_on_malformed_type) {
- const Script& script = Script::Handle(cls.script());
- if (prev_error.IsNull()) {
- error ^= Parser::FormatError(
- script, type.token_pos(), "Error", format, args);
- } else {
- error ^= Parser::FormatErrorWithAppend(
- prev_error, script, type.token_pos(), "Error", format, args);
- }
- if ((finalization == kCanonicalizeWellFormed) ||
- FLAG_error_on_malformed_type) {
- ReportError(error);
- }
+ const Script& script = Script::Handle(cls.script());
+ if (prev_error.IsNull()) {
+ error ^= Parser::FormatError(
+ script, type.token_pos(), "Error", format, args);
+ } else {
+ error ^= Parser::FormatErrorWithAppend(
+ prev_error, script, type.token_pos(), "Error", format, args);
}
- // In checked mode, always mark the type as malformed.
- // In production mode, mark the type as malformed only if its type class is
- // not resolved.
- // In both mode, make the type raw, since it may not be possible to
+ if (FLAG_error_on_malformed_type) {
+ ReportError(error);
+ }
+ type.set_malformed_error(error);
+ // Make the type raw, since it may not be possible to
// properly finalize its type arguments.
- if (FLAG_enable_type_checks || !type.HasResolvedTypeClass()) {
- type.set_malformed_error(error);
- }
+ type.set_type_class(Class::Handle(Object::dynamic_class()));
type.set_arguments(Object::null_abstract_type_arguments());
if (!type.IsFinalized()) {
type.SetIsFinalized();
@@ -2092,12 +2054,10 @@
}
-RawType* ClassFinalizer::NewFinalizedMalformedType(
- const Error& prev_error,
- const Class& cls,
- intptr_t type_pos,
- FinalizationKind finalization,
- const char* format, ...) {
+RawType* ClassFinalizer::NewFinalizedMalformedType(const Error& prev_error,
+ const Class& cls,
+ intptr_t type_pos,
+ const char* format, ...) {
va_list args;
va_start(args, format);
const UnresolvedClass& unresolved_class = UnresolvedClass::Handle(
@@ -2106,7 +2066,7 @@
type_pos));
const Type& type = Type::Handle(
Type::New(unresolved_class, TypeArguments::Handle(), type_pos));
- ReportMalformedType(prev_error, cls, type, finalization, format, args);
+ ReportMalformedType(prev_error, cls, type, format, args);
va_end(args);
ASSERT(type.IsMalformed());
ASSERT(type.IsFinalized());
@@ -2117,11 +2077,10 @@
void ClassFinalizer::FinalizeMalformedType(const Error& prev_error,
const Class& cls,
const Type& type,
- FinalizationKind finalization,
const char* format, ...) {
va_list args;
va_start(args, format);
- ReportMalformedType(prev_error, cls, type, finalization, format, args);
+ ReportMalformedType(prev_error, cls, type, format, args);
va_end(args);
}
diff --git a/runtime/vm/class_finalizer.h b/runtime/vm/class_finalizer.h
index b82cabf..809adee 100644
--- a/runtime/vm/class_finalizer.h
+++ b/runtime/vm/class_finalizer.h
@@ -34,16 +34,11 @@
kDoNotResolve, // Type resolution is postponed.
kResolveTypeParameters, // Resolve type parameters only.
kFinalize, // Type resolution and type finalization are
- // required; a malformed type is tolerated, since
- // the type may be used as a type annotation.
+ // required; replace a malformed type by dynamic.
kCanonicalize, // Same as kFinalize, but with canonicalization.
- kCanonicalizeExpression, // Same as kCanonicalize, but do not tolerate
- // wrong number of type arguments or ambiguous
- // type reference, since the type is not used as
- // a type annotation, but as a type expression.
kCanonicalizeWellFormed // Error-free resolution, finalization, and
// canonicalization are required; a malformed
- // type is not tolerated.
+ // type is marked as such.
};
// Finalize given type while parsing class cls.
@@ -59,9 +54,8 @@
static RawType* NewFinalizedMalformedType(const Error& prev_error,
const Class& cls,
intptr_t type_pos,
- FinalizationKind finalization,
const char* format, ...)
- PRINTF_ATTRIBUTE(5, 6);
+ PRINTF_ATTRIBUTE(4, 5);
// Depending on the given type, finalization mode, and execution mode, mark
// the given type as malformed or report a compile time error.
@@ -70,9 +64,8 @@
static void FinalizeMalformedType(const Error& prev_error,
const Class& cls,
const Type& type,
- FinalizationKind finalization,
const char* format, ...)
- PRINTF_ATTRIBUTE(5, 6);
+ PRINTF_ATTRIBUTE(4, 5);
// Return false if we still have classes pending to be finalized.
static bool AllClassesFinalized();
@@ -145,7 +138,6 @@
static void ReportMalformedType(const Error& prev_error,
const Class& cls,
const Type& type,
- FinalizationKind finalization,
const char* format,
va_list args);
static void ReportError(const Error& error);
diff --git a/runtime/vm/constants_arm.h b/runtime/vm/constants_arm.h
index 5c1dd00..63a88e9 100644
--- a/runtime/vm/constants_arm.h
+++ b/runtime/vm/constants_arm.h
@@ -405,6 +405,8 @@
kPCReadOffset = 8
};
+ static const int32_t kNopInstruction = // nop
+ ((AL << kConditionShift) | (0x32 << 20) | (0xf << 12));
static const int32_t kBreakPointInstruction = // svc #kBreakpointSvcCode
((AL << kConditionShift) | (0xf << 24) | kBreakpointSvcCode);
static const int kBreakPointInstructionSize = kInstrSize;
diff --git a/runtime/vm/dart_api_impl.cc b/runtime/vm/dart_api_impl.cc
index d298335..4b91917 100644
--- a/runtime/vm/dart_api_impl.cc
+++ b/runtime/vm/dart_api_impl.cc
@@ -3565,7 +3565,7 @@
"%s: argument 'arg_index' out of range. Expected 0..%d but saw %d.",
CURRENT_FUNC, arguments->NativeArgCount() - 1, arg_index);
}
- Isolate* isolate = Isolate::Current();
+ Isolate* isolate = arguments->isolate();
DARTSCOPE(isolate);
const Object& obj = Object::Handle(isolate,
arguments->NativeArgAt(arg_index));
@@ -3593,14 +3593,48 @@
DART_EXPORT void Dart_SetReturnValue(Dart_NativeArguments args,
Dart_Handle retval) {
- const Object& ret_obj = Object::Handle(Api::UnwrapHandle(retval));
- if (!ret_obj.IsNull() && !ret_obj.IsInstance()) {
+ NativeArguments* arguments = reinterpret_cast<NativeArguments*>(args);
+ Isolate* isolate = arguments->isolate();
+ CHECK_ISOLATE(isolate);
+ if ((retval != Api::Null()) && (!Api::IsInstance(retval))) {
+ const Object& ret_obj = Object::Handle(Api::UnwrapHandle(retval));
FATAL1("Return value check failed: saw '%s' expected a dart Instance.",
ret_obj.ToCString());
}
- NoGCScope no_gc_scope;
+ ASSERT(retval != 0);
+ Api::SetReturnValue(arguments, retval);
+}
+
+
+DART_EXPORT void Dart_SetBooleanReturnValue(Dart_NativeArguments args,
+ bool retval) {
NativeArguments* arguments = reinterpret_cast<NativeArguments*>(args);
- arguments->SetReturn(ret_obj);
+ arguments->SetReturn(retval ? Bool::True() : Bool::False());
+}
+
+
+DART_EXPORT void Dart_SetIntegerReturnValue(Dart_NativeArguments args,
+ intptr_t retval) {
+ NativeArguments* arguments = reinterpret_cast<NativeArguments*>(args);
+ Isolate* isolate = arguments->isolate();
+ CHECK_ISOLATE(isolate);
+ if (Smi::IsValid64(retval)) {
+ Api::SetSmiReturnValue(arguments, retval);
+ } else {
+ // Slow path for Mints and Bigints.
+ ASSERT_CALLBACK_STATE(isolate);
+ Api::SetIntegerReturnValue(arguments, retval);
+ }
+}
+
+
+DART_EXPORT void Dart_SetDoubleReturnValue(Dart_NativeArguments args,
+ double retval) {
+ NativeArguments* arguments = reinterpret_cast<NativeArguments*>(args);
+ Isolate* isolate = arguments->isolate();
+ CHECK_ISOLATE(isolate);
+ ASSERT_CALLBACK_STATE(isolate);
+ Api::SetDoubleReturnValue(arguments, retval);
}
diff --git a/runtime/vm/dart_api_impl.h b/runtime/vm/dart_api_impl.h
index c3b66e6..95b1b1a 100644
--- a/runtime/vm/dart_api_impl.h
+++ b/runtime/vm/dart_api_impl.h
@@ -6,6 +6,7 @@
#define VM_DART_API_IMPL_H_
#include "vm/allocation.h"
+#include "vm/native_arguments.h"
#include "vm/object.h"
namespace dart {
@@ -147,6 +148,11 @@
return !raw->IsHeapObject();
}
+ // Returns true if the handle holds a Dart Instance.
+ static bool IsInstance(Dart_Handle handle) {
+ return (ClassId(handle) >= kInstanceCid);
+ }
+
// Returns the value of a Smi.
static intptr_t SmiValue(Dart_Handle handle) {
// TODO(turnidge): Assumes RawObject* is at offset zero. Fix.
@@ -187,6 +193,20 @@
// Helper function to get the peer value of an external string object.
static bool ExternalStringGetPeerHelper(Dart_Handle object, void** peer);
+ // Helper function to set the return value of native functions.
+ static void SetReturnValue(NativeArguments* args, Dart_Handle retval) {
+ args->SetReturnUnsafe(UnwrapHandle(retval));
+ }
+ static void SetSmiReturnValue(NativeArguments* args, intptr_t retval) {
+ args->SetReturnUnsafe(Smi::New(retval));
+ }
+ static void SetIntegerReturnValue(NativeArguments* args, intptr_t retval) {
+ args->SetReturnUnsafe(Integer::New(retval));
+ }
+ static void SetDoubleReturnValue(NativeArguments* args, double retval) {
+ args->SetReturnUnsafe(Double::New(retval));
+ }
+
private:
// Thread local key used by the API. Currently holds the current
// ApiNativeScope if any.
@@ -225,6 +245,9 @@
return reinterpret_cast<Dart_Handle>(Api::AcquiredError(isolate)); \
} \
+#define ASSERT_CALLBACK_STATE(isolate) \
+ ASSERT(isolate->no_callback_scope_depth() == 0)
+
} // namespace dart.
#endif // VM_DART_API_IMPL_H_
diff --git a/runtime/vm/debugger_api_impl.cc b/runtime/vm/debugger_api_impl.cc
index b3c3739..32e8a3a 100644
--- a/runtime/vm/debugger_api_impl.cc
+++ b/runtime/vm/debugger_api_impl.cc
@@ -523,9 +523,16 @@
DARTSCOPE(isolate);
UNWRAP_AND_CHECK_PARAM(Type, type, type_in);
+ if (!type.IsFinalized()) {
+ return Api::NewError("%s: type in 'type_in' is not a finalized type",
+ CURRENT_FUNC);
+ }
+ if (!type.IsInstantiated()) {
+ return Api::NewError("%s: type in 'type_in' is not an instantiated type",
+ CURRENT_FUNC);
+ }
const Class& cls= Class::Handle(type.type_class());
- intptr_t num_expected_type_arguments = cls.NumTypeParameters();
- if (num_expected_type_arguments == 0) {
+ if (cls.NumTypeParameters() == 0) {
// The super type has no type parameters or it is already instantiated
// just return it.
const AbstractType& type = AbstractType::Handle(cls.super_type());
@@ -536,26 +543,25 @@
}
// Set up the type arguments array for the super class type.
const Class& super_cls = Class::Handle(cls.SuperClass());
- num_expected_type_arguments = super_cls.NumTypeParameters();
+ intptr_t num_expected_type_arguments = super_cls.NumTypeArguments();
+ TypeArguments& super_type_args_array = TypeArguments::Handle();
const AbstractTypeArguments& type_args_array =
AbstractTypeArguments::Handle(type.arguments());
- const TypeArguments& super_type_args_array =
- TypeArguments::Handle(TypeArguments::New(num_expected_type_arguments));
- AbstractType& type_arg = AbstractType::Handle();
- intptr_t index_offset =
- super_cls.NumTypeArguments() - num_expected_type_arguments;
- for (intptr_t i = 0; i < num_expected_type_arguments; i++) {
- type_arg ^= type_args_array.TypeAt(i + index_offset);
- super_type_args_array.SetTypeAt(i, type_arg);
+ if (!type_args_array.IsNull() && (num_expected_type_arguments > 0)) {
+ super_type_args_array = TypeArguments::New(num_expected_type_arguments);
+ AbstractType& type_arg = AbstractType::Handle();
+ for (intptr_t i = 0; i < num_expected_type_arguments; i++) {
+ type_arg ^= type_args_array.TypeAt(i);
+ super_type_args_array.SetTypeAt(i, type_arg);
+ }
}
// Construct the super type object, canonicalize it and return.
Type& instantiated_type = Type::Handle(
Type::New(super_cls, super_type_args_array, Scanner::kDummyTokenIndex));
ASSERT(!instantiated_type.IsNull());
- instantiated_type ^= ClassFinalizer::FinalizeType(
- super_cls, instantiated_type, ClassFinalizer::kCanonicalize);
- return Api::NewHandle(isolate, instantiated_type.raw());
+ instantiated_type.SetIsFinalized();
+ return Api::NewHandle(isolate, instantiated_type.Canonicalize());
}
diff --git a/runtime/vm/debugger_api_impl_test.cc b/runtime/vm/debugger_api_impl_test.cc
index 2f53eb8..7890195 100644
--- a/runtime/vm/debugger_api_impl_test.cc
+++ b/runtime/vm/debugger_api_impl_test.cc
@@ -1462,6 +1462,7 @@
"}\n"
"class Test5<A, B, C> extends Test4<A, B> {\n"
"}\n"
+ "var s = new Set();\n"
"int main() {\n"
"}\n";
@@ -1479,6 +1480,8 @@
Dart_Handle Test5_name = Dart_NewStringFromCString("Test5");
Dart_Handle object_name = Dart_NewStringFromCString("Object");
Dart_Handle int_name = Dart_NewStringFromCString("int");
+ Dart_Handle set_name = Dart_NewStringFromCString("Set");
+ Dart_Handle iterable_name = Dart_NewStringFromCString("IterableBase");
Dart_Handle object_type = Dart_GetType(core_lib, object_name, 0, NULL);
Dart_Handle int_type = Dart_GetType(core_lib, int_name, 0, NULL);
@@ -1494,14 +1497,14 @@
Dart_Handle Test3_type = Dart_GetType(script_lib, Test3_name, 0, NULL);
type_args = Dart_NewList(2);
Dart_ListSetAt(type_args, 0, int_type);
- Dart_ListSetAt(type_args, 1, int_type);
+ Dart_ListSetAt(type_args, 1, Test_type);
Dart_Handle Test4_int_type = Dart_GetType(script_lib,
Test4_name,
2,
&type_args);
type_args = Dart_NewList(3);
Dart_ListSetAt(type_args, 0, int_type);
- Dart_ListSetAt(type_args, 1, int_type);
+ Dart_ListSetAt(type_args, 1, Test_type);
Dart_ListSetAt(type_args, 2, int_type);
Dart_Handle Test5_int_type = Dart_GetType(script_lib,
Test5_name,
@@ -1535,6 +1538,14 @@
const Type& actual_type = Api::UnwrapTypeHandle(isolate, super_type);
EXPECT(expected_type.raw() == actual_type.raw());
}
+ {
+ Dart_Handle set_type = Dart_GetType(core_lib, set_name, 0, NULL);
+ Dart_Handle super_type = Dart_GetSupertype(set_type);
+ Dart_Handle iterable_type = Dart_GetType(core_lib, iterable_name, 0, NULL);
+ const Type& expected_type = Api::UnwrapTypeHandle(isolate, iterable_type);
+ const Type& actual_type = Api::UnwrapTypeHandle(isolate, super_type);
+ EXPECT(expected_type.raw() == actual_type.raw());
+ }
}
} // namespace dart
diff --git a/runtime/vm/disassembler_arm.cc b/runtime/vm/disassembler_arm.cc
index bcb2b45..6acd20f 100644
--- a/runtime/vm/disassembler_arm.cc
+++ b/runtime/vm/disassembler_arm.cc
@@ -1379,6 +1379,10 @@
} else {
Unknown(instr);
}
+ } else if ((instr->Bits(8, 4) == 1) && (instr->Bit(4) == 0) &&
+ (instr->Bits(20, 2) == 3) && (instr->Bits(23, 2) == 3) &&
+ (instr->Bit(7) == 1) && (instr->Bits(16, 4) == 10)) {
+ Format(instr, "vzipqw 'qd, 'qm");
} else if ((instr->Bits(8, 4) == 8) && (instr->Bit(4) == 1) &&
(instr->Bits(23, 2) == 2)) {
Format(instr, "vceqq'sz 'qd, 'qn, 'qm");
diff --git a/runtime/vm/disassembler_ia32.cc b/runtime/vm/disassembler_ia32.cc
index 49664cc..5f1131e 100644
--- a/runtime/vm/disassembler_ia32.cc
+++ b/runtime/vm/disassembler_ia32.cc
@@ -226,6 +226,10 @@
// Returns NULL if the instruction is not handled here.
static const char* F0Mnem(uint8_t f0byte) {
switch (f0byte) {
+ case 0x12: return "movhlps";
+ case 0x14: return "unpcklps";
+ case 0x15: return "unpckhps";
+ case 0x16: return "movlhps";
case 0xA2: return "cpuid";
case 0x31: return "rdtsc";
case 0xBE: return "movsx_b";
@@ -258,6 +262,16 @@
}
+static bool IsTwoXmmRegInstruction(uint8_t f0byte) {
+ return f0byte == 0x28 || f0byte == 0x11 || f0byte == 0x12 ||
+ f0byte == 0x14 || f0byte == 0x15 || f0byte == 0x16 ||
+ f0byte == 0x51 || f0byte == 0x52 || f0byte == 0x53 ||
+ f0byte == 0x54 || f0byte == 0x56 || f0byte == 0x58 ||
+ f0byte == 0x59 || f0byte == 0x5C || f0byte == 0x5D ||
+ f0byte == 0x5E || f0byte == 0x5F;
+}
+
+
// The implementation of x86 decoding based on the above tables.
class X86Decoder : public ValueObject {
public:
@@ -1362,22 +1376,6 @@
PrintCPURegister(regop);
Print(",cl");
}
- } else if (f0byte == 0x28) {
- // movaps
- Print(f0mnem);
- int mod, regop, rm;
- GetModRm(*data, &mod, ®op, &rm);
- Print(" ");
- PrintXmmRegister(regop);
- Print(",");
- data += PrintRightXmmOperand(data);
- } else if (f0byte == 0x11) {
- Print("movups ");
- int mod, regop, rm;
- GetModRm(*data, &mod, ®op, &rm);
- data += PrintRightXmmOperand(data);
- Print(",");
- PrintXmmRegister(regop);
} else if (f0byte == 0x10) {
int mod, regop, rm;
GetModRm(*data, &mod, ®op, &rm);
@@ -1385,10 +1383,7 @@
PrintXmmRegister(regop);
Print(",");
data += PrintRightOperand(data);
- } else if (f0byte == 0x51 || f0byte == 0x52 || f0byte == 0x53 ||
- f0byte == 0x54 || f0byte == 0x56 || f0byte == 0x58 ||
- f0byte == 0x59 || f0byte == 0x5C || f0byte == 0x5D ||
- f0byte == 0x5E || f0byte == 0x5F) {
+ } else if (IsTwoXmmRegInstruction(f0byte)) {
int mod, regop, rm;
GetModRm(*data, &mod, ®op, &rm);
Print(f0mnem);
@@ -1598,6 +1593,22 @@
} else {
UNIMPLEMENTED();
}
+ } else if (*data == 0x14) {
+ int mod, regop, rm;
+ GetModRm(*(data+1), &mod, ®op, &rm);
+ Print("unpcklpd ");
+ PrintXmmRegister(regop);
+ Print(",");
+ PrintXmmRegister(rm);
+ data += 2;
+ } else if (*data == 0x15) {
+ int mod, regop, rm;
+ GetModRm(*(data+1), &mod, ®op, &rm);
+ Print("unpckhpd ");
+ PrintXmmRegister(regop);
+ Print(",");
+ PrintXmmRegister(rm);
+ data += 2;
} else {
UNIMPLEMENTED();
}
diff --git a/runtime/vm/disassembler_x64.cc b/runtime/vm/disassembler_x64.cc
index 4af7ba3..f42ebac 100644
--- a/runtime/vm/disassembler_x64.cc
+++ b/runtime/vm/disassembler_x64.cc
@@ -1268,7 +1268,11 @@
current += PrintRightXMMOperand(current);
} else {
const char* mnemonic = "?";
- if (opcode == 0x54) {
+ if (opcode == 0x14) {
+ mnemonic = "unpcklpd";
+ } else if (opcode == 0x15) {
+ mnemonic = "unpckhpd";
+ } else if (opcode == 0x54) {
mnemonic = "andpd";
} else if (opcode == 0x56) {
mnemonic = "orpd";
@@ -1425,12 +1429,18 @@
byte_size_operand_ = idesc.byte_size_operation;
current += PrintOperands(idesc.mnem, idesc.op_order_, current);
- } else if (opcode == 0x51 || opcode == 0x52 || opcode == 0x53 ||
- opcode == 0x54 || opcode == 0x56 || opcode == 0x57 ||
- opcode == 0x58 || opcode == 0x59 || opcode == 0x5C ||
- opcode == 0x5D || opcode == 0x5E || opcode == 0x5F) {
+ } else if (opcode == 0x12 || opcode == 0x14 || opcode == 0x15 ||
+ opcode == 0x16 || opcode == 0x51 || opcode == 0x52 ||
+ opcode == 0x53 || opcode == 0x54 || opcode == 0x56 ||
+ opcode == 0x57 || opcode == 0x58 || opcode == 0x59 ||
+ opcode == 0x5C || opcode == 0x5D || opcode == 0x5E ||
+ opcode == 0x5F) {
const char* mnemonic = NULL;
switch (opcode) {
+ case 0x12: mnemonic = "movhlps"; break;
+ case 0x14: mnemonic = "unpcklps"; break;
+ case 0x15: mnemonic = "unpckhps"; break;
+ case 0x16: mnemonic = "movlhps"; break;
case 0x51: mnemonic = "sqrtps"; break;
case 0x52: mnemonic = "rsqrtps"; break;
case 0x53: mnemonic = "rcpps"; break;
diff --git a/runtime/vm/exceptions.cc b/runtime/vm/exceptions.cc
index 0f7b8a4..2712f6f 100644
--- a/runtime/vm/exceptions.cc
+++ b/runtime/vm/exceptions.cc
@@ -671,9 +671,9 @@
library = Library::IsolateLibrary();
class_name = &Symbols::IsolateUnhandledException();
break;
- case kFiftyThreeBitOverflowError:
+ case kJavascriptIntegerOverflowError:
library = Library::CoreLibrary();
- class_name = &Symbols::FiftyThreeBitOverflowError();
+ class_name = &Symbols::JavascriptIntegerOverflowError();
break;
case kAssertion:
library = Library::CoreLibrary();
diff --git a/runtime/vm/exceptions.h b/runtime/vm/exceptions.h
index 04623a4..79f7e3a 100644
--- a/runtime/vm/exceptions.h
+++ b/runtime/vm/exceptions.h
@@ -52,7 +52,7 @@
kNullThrown,
kIsolateSpawn,
kIsolateUnhandledException,
- kFiftyThreeBitOverflowError,
+ kJavascriptIntegerOverflowError,
kAssertion,
kCast,
kType,
diff --git a/runtime/vm/flow_graph_builder.cc b/runtime/vm/flow_graph_builder.cc
index eb6822b..900e7ff 100644
--- a/runtime/vm/flow_graph_builder.cc
+++ b/runtime/vm/flow_graph_builder.cc
@@ -1840,8 +1840,9 @@
char name[64];
OS::SNPrint(name, 64, ":tmp_local%"Pd, index);
LocalVariable* var =
- new LocalVariable(0, String::ZoneHandle(Symbols::New(name)),
- Type::ZoneHandle(Type::DynamicType()));
+ new LocalVariable(0,
+ String::ZoneHandle(Symbols::New(name)),
+ *value->Type()->ToAbstractType());
var->set_index(index);
return var;
}
@@ -1978,7 +1979,6 @@
ReturnDefinition(new ConstantInstr(closure));
return;
}
- Value* receiver = NULL;
if (function.IsNonImplicitClosureFunction()) {
// The context scope may have already been set by the non-optimizing
// compiler. If it was not, set it here.
@@ -1990,40 +1990,109 @@
ASSERT(function.context_scope() == ContextScope::null());
function.set_context_scope(context_scope);
}
- receiver = BuildNullValue();
+ ZoneGrowableArray<PushArgumentInstr*>* arguments =
+ new ZoneGrowableArray<PushArgumentInstr*>(2);
+ ASSERT(function.context_scope() != ContextScope::null());
+
+ // The function type of a closure may have type arguments. In that case,
+ // pass the type arguments of the instantiator.
+ const Class& cls = Class::ZoneHandle(function.signature_class());
+ ASSERT(!cls.IsNull());
+ const bool requires_type_arguments = cls.HasTypeArguments();
+ Value* type_arguments = NULL;
+ if (requires_type_arguments) {
+ ASSERT(cls.type_arguments_field_offset() ==
+ Closure::type_arguments_offset());
+ const Class& instantiator_class = Class::Handle(
+ owner()->parsed_function()->function().Owner());
+ type_arguments = BuildInstantiatorTypeArguments(node->token_pos(),
+ instantiator_class,
+ NULL);
+ arguments->Add(PushArgument(type_arguments));
+
+ Value* instantiator_val = Bind(new ConstantInstr(
+ Smi::ZoneHandle(Smi::New(StubCode::kNoInstantiator))));
+ arguments->Add(PushArgument(instantiator_val));
+ }
+ AllocateObjectInstr* alloc = new AllocateObjectInstr(node->token_pos(),
+ cls,
+ arguments);
+ alloc->set_closure_function(function);
+
+ // Create fake fields for function and context. Only the context field is
+ // stored at the allocation to be used later when inlining a closure call.
+ const Field& function_field =
+ Field::ZoneHandle(
+ Field::New(Symbols::ClosureFunctionField(),
+ false, // !static
+ false, // !final
+ false, // !const
+ alloc->cls(),
+ 0)); // No token position.
+ function_field.SetOffset(Closure::function_offset());
+ const Field& context_field =
+ Field::ZoneHandle(Field::New(
+ Symbols::ClosureContextField(),
+ false, // !static
+ false, // !final
+ false, // !const
+ alloc->cls(),
+ 0)); // No token position.
+ context_field.SetOffset(Closure::context_offset());
+ alloc->set_context_field(context_field);
+
+ Value* closure_val = Bind(alloc);
+ { LocalVariable* tmp_var = EnterTempLocalScope(closure_val);
+ // Store function.
+ Value* tmp_val = Bind(new LoadLocalInstr(*tmp_var));
+ Value* func_val =
+ Bind(new ConstantInstr(Function::ZoneHandle(function.raw())));
+ Do(new StoreInstanceFieldInstr(function_field,
+ tmp_val,
+ func_val,
+ kEmitStoreBarrier));
+ // Store current context.
+ tmp_val = Bind(new LoadLocalInstr(*tmp_var));
+ Value* context = Bind(new CurrentContextInstr());
+ Do(new StoreInstanceFieldInstr(context_field,
+ tmp_val,
+ context,
+ kEmitStoreBarrier));
+ ReturnDefinition(ExitTempLocalScope(tmp_var));
+ }
} else {
ASSERT(function.IsImplicitInstanceClosureFunction());
ValueGraphVisitor for_receiver(owner(), temp_index());
node->receiver()->Visit(&for_receiver);
Append(for_receiver);
- receiver = for_receiver.value();
- }
- PushArgumentInstr* push_receiver = PushArgument(receiver);
- ZoneGrowableArray<PushArgumentInstr*>* arguments =
- new ZoneGrowableArray<PushArgumentInstr*>(2);
- arguments->Add(push_receiver);
- ASSERT(function.context_scope() != ContextScope::null());
+ Value* receiver = for_receiver.value();
- // The function type of a closure may have type arguments. In that case, pass
- // the type arguments of the instantiator. Otherwise, pass null object.
- const Class& cls = Class::Handle(function.signature_class());
- ASSERT(!cls.IsNull());
- const bool requires_type_arguments = cls.HasTypeArguments();
- Value* type_arguments = NULL;
- if (requires_type_arguments) {
- ASSERT(!function.IsImplicitStaticClosureFunction());
- const Class& instantiator_class = Class::Handle(
- owner()->parsed_function()->function().Owner());
- type_arguments = BuildInstantiatorTypeArguments(node->token_pos(),
- instantiator_class,
- NULL);
- } else {
- type_arguments = BuildNullValue();
+ PushArgumentInstr* push_receiver = PushArgument(receiver);
+ ZoneGrowableArray<PushArgumentInstr*>* arguments =
+ new ZoneGrowableArray<PushArgumentInstr*>(2);
+ arguments->Add(push_receiver);
+ ASSERT(function.context_scope() != ContextScope::null());
+
+ // The function type of a closure may have type arguments. In that case,
+ // pass the type arguments of the instantiator. Otherwise, pass null object.
+ const Class& cls = Class::Handle(function.signature_class());
+ ASSERT(!cls.IsNull());
+ const bool requires_type_arguments = cls.HasTypeArguments();
+ Value* type_arguments = NULL;
+ if (requires_type_arguments) {
+ const Class& instantiator_class = Class::Handle(
+ owner()->parsed_function()->function().Owner());
+ type_arguments = BuildInstantiatorTypeArguments(node->token_pos(),
+ instantiator_class,
+ NULL);
+ } else {
+ type_arguments = BuildNullValue();
+ }
+ PushArgumentInstr* push_type_arguments = PushArgument(type_arguments);
+ arguments->Add(push_type_arguments);
+ ReturnDefinition(
+ new CreateClosureInstr(node->function(), arguments, node->token_pos()));
}
- PushArgumentInstr* push_type_arguments = PushArgument(type_arguments);
- arguments->Add(push_type_arguments);
- ReturnDefinition(
- new CreateClosureInstr(node->function(), arguments, node->token_pos()));
}
@@ -2200,7 +2269,10 @@
BuildConstructorTypeArguments(node, allocate_arguments);
}
- allocation = new AllocateObjectInstr(node, allocate_arguments);
+ allocation = new AllocateObjectInstr(
+ node->token_pos(),
+ Class::ZoneHandle(node->constructor().Owner()),
+ allocate_arguments);
}
return Bind(allocation);
}
diff --git a/runtime/vm/flow_graph_inliner.cc b/runtime/vm/flow_graph_inliner.cc
index 229f7fc..247b0fe 100644
--- a/runtime/vm/flow_graph_inliner.cc
+++ b/runtime/vm/flow_graph_inliner.cc
@@ -681,6 +681,13 @@
new LoadFieldInstr(new Value(closure),
Closure::context_offset(),
Type::ZoneHandle());
+ AllocateObjectInstr* alloc =
+ closure_call->ArgumentAt(0)->AsAllocateObject();
+ if ((alloc != NULL) && !alloc->closure_function().IsNull()) {
+ ASSERT(!alloc->context_field().IsNull());
+ context->set_field(&alloc->context_field());
+ }
+
context->set_ssa_temp_index(caller_graph()->alloc_ssa_temp_index());
context->InsertAfter(callee_entry);
StoreContextInstr* set_context =
@@ -803,9 +810,19 @@
ClosureCallInstr* call = calls[i];
// Find the closure of the callee.
ASSERT(call->ArgumentCount() > 0);
- const CreateClosureInstr* closure =
+ Function& target = Function::ZoneHandle();
+ CreateClosureInstr* closure =
call->ArgumentAt(0)->AsCreateClosure();
- if (closure == NULL) {
+ if (closure != NULL) {
+ target ^= closure->function().raw();
+ }
+ AllocateObjectInstr* alloc =
+ call->ArgumentAt(0)->AsAllocateObject();
+ if ((alloc != NULL) && !alloc->closure_function().IsNull()) {
+ target ^= alloc->closure_function().raw();
+ ASSERT(target.signature_class() == alloc->cls().raw());
+ }
+ if (target.IsNull()) {
TRACE_INLINING(OS::Print(" Bailout: non-closure operator\n"));
continue;
}
@@ -814,7 +831,7 @@
arguments.Add(call->PushArgumentAt(i)->value());
}
InlinedCallData call_data(call, &arguments);
- if (TryInlining(closure->function(),
+ if (TryInlining(target,
call->argument_names(),
&call_data)) {
InlineCall(&call_data);
@@ -1180,6 +1197,10 @@
callee_entry->AsGraphEntry()->normal_entry();
cursor->LinkTo(target->next());
target->ReplaceAsPredecessorWith(current_block);
+ // Unuse all inputs of the graph entry and the normal entry. They are
+ // not in the graph anymore.
+ callee_entry->UnuseAllInputs();
+ target->UnuseAllInputs();
// All blocks that were dominated by the normal entry are now
// dominated by the current block.
for (intptr_t j = 0;
@@ -1230,6 +1251,8 @@
if (callee_entry->IsGraphEntry()) {
// Unshared.
true_target = callee_entry->AsGraphEntry()->normal_entry();
+ // Unuse all inputs of the graph entry. It is not in the graph anymore.
+ callee_entry->UnuseAllInputs();
} else if (callee_entry->IsTargetEntry()) {
// Shared inlined body and this is the first entry. We have already
// constructed a join and this target jumps to it.
diff --git a/runtime/vm/flow_graph_optimizer.cc b/runtime/vm/flow_graph_optimizer.cc
index 170f5a4..fce131c 100644
--- a/runtime/vm/flow_graph_optimizer.cc
+++ b/runtime/vm/flow_graph_optimizer.cc
@@ -592,19 +592,9 @@
}
-static bool HasOnlyTwoSmis(const ICData& ic_data) {
+static bool HasOnlyTwoOf(const ICData& ic_data, intptr_t cid) {
return (ic_data.NumberOfChecks() == 1) &&
- ICDataHasReceiverArgumentClassIds(ic_data, kSmiCid, kSmiCid);
-}
-
-static bool HasOnlyTwoFloat32x4s(const ICData& ic_data) {
- return (ic_data.NumberOfChecks() == 1) &&
- ICDataHasReceiverArgumentClassIds(ic_data, kFloat32x4Cid, kFloat32x4Cid);
-}
-
-static bool HasOnlyTwoUint32x4s(const ICData& ic_data) {
- return (ic_data.NumberOfChecks() == 1) &&
- ICDataHasReceiverArgumentClassIds(ic_data, kUint32x4Cid, kUint32x4Cid);
+ ICDataHasReceiverArgumentClassIds(ic_data, cid, cid);
}
// Returns false if the ICData contains anything other than the 4 combinations
@@ -1030,7 +1020,7 @@
switch (op_kind) {
case Token::kADD:
case Token::kSUB:
- if (HasOnlyTwoSmis(ic_data)) {
+ if (HasOnlyTwoOf(ic_data, kSmiCid)) {
// Don't generate smi code if the IC data is marked because
// of an overflow.
operands_type = (ic_data.deopt_reason() == kDeoptBinarySmiOp)
@@ -1044,14 +1034,14 @@
operands_type = kMintCid;
} else if (ShouldSpecializeForDouble(ic_data)) {
operands_type = kDoubleCid;
- } else if (HasOnlyTwoFloat32x4s(ic_data)) {
+ } else if (HasOnlyTwoOf(ic_data, kFloat32x4Cid)) {
operands_type = kFloat32x4Cid;
} else {
return false;
}
break;
case Token::kMUL:
- if (HasOnlyTwoSmis(ic_data)) {
+ if (HasOnlyTwoOf(ic_data, kSmiCid)) {
// Don't generate smi code if the IC data is marked because of an
// overflow.
// TODO(fschneider): Add unboxed mint multiplication.
@@ -1059,23 +1049,24 @@
operands_type = kSmiCid;
} else if (ShouldSpecializeForDouble(ic_data)) {
operands_type = kDoubleCid;
- } else if (HasOnlyTwoFloat32x4s(ic_data)) {
+ } else if (HasOnlyTwoOf(ic_data, kFloat32x4Cid)) {
operands_type = kFloat32x4Cid;
} else {
return false;
}
break;
case Token::kDIV:
- if (ShouldSpecializeForDouble(ic_data) || HasOnlyTwoSmis(ic_data)) {
+ if (ShouldSpecializeForDouble(ic_data) ||
+ HasOnlyTwoOf(ic_data, kSmiCid)) {
operands_type = kDoubleCid;
- } else if (HasOnlyTwoFloat32x4s(ic_data)) {
+ } else if (HasOnlyTwoOf(ic_data, kFloat32x4Cid)) {
operands_type = kFloat32x4Cid;
} else {
return false;
}
break;
case Token::kMOD:
- if (HasOnlyTwoSmis(ic_data)) {
+ if (HasOnlyTwoOf(ic_data, kSmiCid)) {
operands_type = kSmiCid;
} else {
return false;
@@ -1084,11 +1075,11 @@
case Token::kBIT_AND:
case Token::kBIT_OR:
case Token::kBIT_XOR:
- if (HasOnlyTwoSmis(ic_data)) {
+ if (HasOnlyTwoOf(ic_data, kSmiCid)) {
operands_type = kSmiCid;
} else if (HasTwoMintOrSmi(ic_data)) {
operands_type = kMintCid;
- } else if (HasOnlyTwoUint32x4s(ic_data)) {
+ } else if (HasOnlyTwoOf(ic_data, kUint32x4Cid)) {
operands_type = kUint32x4Cid;
} else {
return false;
@@ -1096,7 +1087,7 @@
break;
case Token::kSHR:
case Token::kSHL:
- if (HasOnlyTwoSmis(ic_data)) {
+ if (HasOnlyTwoOf(ic_data, kSmiCid)) {
// Left shift may overflow from smi into mint or big ints.
// Don't generate smi code if the IC data is marked because
// of an overflow.
@@ -1117,7 +1108,7 @@
}
break;
case Token::kTRUNCDIV:
- if (HasOnlyTwoSmis(ic_data)) {
+ if (HasOnlyTwoOf(ic_data, kSmiCid)) {
if (ic_data.deopt_reason() == kDeoptBinarySmiOp) return false;
operands_type = kSmiCid;
} else {
@@ -1336,7 +1327,6 @@
}
AddToGuardedFields(field);
}
- load->set_field_name(String::Handle(field.name()).ToCString());
// Discard the environment from the original instruction because the load
// can't deoptimize.
@@ -2053,6 +2043,26 @@
ReplaceCall(call, minmax);
return true;
}
+ case MethodRecognizer::kFloat32x4WithZWInXY:
+ case MethodRecognizer::kFloat32x4InterleaveXY:
+ case MethodRecognizer::kFloat32x4InterleaveZW:
+ case MethodRecognizer::kFloat32x4InterleaveXYPairs:
+ case MethodRecognizer::kFloat32x4InterleaveZWPairs: {
+ Definition* left = call->ArgumentAt(0);
+ Definition* right = call->ArgumentAt(1);
+ // Type check left.
+ AddCheckClass(left,
+ ICData::ZoneHandle(
+ call->ic_data()->AsUnaryClassChecksForArgNr(0)),
+ call->deopt_id(),
+ call->env(),
+ call);
+ Float32x4TwoArgShuffleInstr* two_arg_shuffle =
+ new Float32x4TwoArgShuffleInstr(recognized_kind, new Value(left),
+ new Value(right), call->deopt_id());
+ ReplaceCall(call, two_arg_shuffle);
+ return true;
+ }
case MethodRecognizer::kFloat32x4Scale: {
Definition* left = call->ArgumentAt(0);
Definition* right = call->ArgumentAt(1);
@@ -2757,15 +2767,14 @@
Instruction* current_instruction) {
ASSERT(ic_data.num_args_tested() == 2);
ASSERT(comp->operation_cid() == kIllegalCid);
- Instruction* instr = current_iterator()->Current();
- if (HasOnlyTwoSmis(ic_data)) {
- InsertBefore(instr,
+ if (HasOnlyTwoOf(ic_data, kSmiCid)) {
+ InsertBefore(current_instruction,
new CheckSmiInstr(comp->left()->Copy(), comp->deopt_id()),
- instr->env(),
+ current_instruction->env(),
Definition::kEffect);
- InsertBefore(instr,
+ InsertBefore(current_instruction,
new CheckSmiInstr(comp->right()->Copy(), comp->deopt_id()),
- instr->env(),
+ current_instruction->env(),
Definition::kEffect);
comp->set_operation_cid(kSmiCid);
} else if (HasTwoMintOrSmi(ic_data) &&
@@ -2780,11 +2789,11 @@
// We cannot use double comparison on two Smi-s.
ASSERT(comp->operation_cid() == kIllegalCid);
} else {
- InsertBefore(instr,
+ InsertBefore(current_instruction,
new CheckEitherNonSmiInstr(comp->left()->Copy(),
comp->right()->Copy(),
comp->deopt_id()),
- instr->env(),
+ current_instruction->env(),
Definition::kEffect);
comp->set_operation_cid(kDoubleCid);
}
@@ -2872,10 +2881,54 @@
}
+// Returns true if we converted EqualityCompare to StrictCompare.
+template <typename T>
+bool FlowGraphOptimizer::StrictifyEqualityCompareWithICData(
+ EqualityCompareInstr* compare,
+ const ICData& unary_ic_data,
+ T current_instruction) {
+ ASSERT(unary_ic_data.num_args_tested() == 1);
+ if (unary_ic_data.NumberOfChecks() <= FLAG_max_polymorphic_checks) {
+ // If possible classes do not override Object's equality then replace
+ // with strict equality.
+ Function& target = Function::Handle();
+ Class& targets_class = Class::Handle();
+ for (intptr_t i = 0; i < unary_ic_data.NumberOfChecks(); i++) {
+ intptr_t cid = kIllegalCid;
+ unary_ic_data.GetOneClassCheckAt(i, &cid, &target);
+ targets_class = target.Owner();
+ if (targets_class.id() != kInstanceCid) {
+ // Overriden equality operator.
+ return false;
+ }
+ }
+ AddCheckClass(compare->left()->definition(),
+ unary_ic_data,
+ compare->deopt_id(),
+ current_instruction->env(),
+ current_instruction);
+ ASSERT((compare->kind() == Token::kEQ) || (compare->kind() == Token::kNE));
+ Token::Kind strict_kind = (compare->kind() == Token::kEQ) ?
+ Token::kEQ_STRICT : Token::kNE_STRICT;
+ StrictCompareInstr* strict_comp =
+ new StrictCompareInstr(compare->token_pos(),
+ strict_kind,
+ compare->left()->Copy(),
+ compare->right()->Copy());
+ // Numbers override equality and are therefore not part of this conversion.
+ strict_comp->set_needs_number_check(false);
+ current_instruction->ReplaceWith(strict_comp, current_iterator());
+ return true;
+ }
+ return false;
+}
+
+
template <typename T>
void FlowGraphOptimizer::HandleEqualityCompare(EqualityCompareInstr* comp,
T current_instruction) {
if (StrictifyEqualityCompare(comp, current_instruction)) {
+ // Based on input types, equality converted to strict-equality.
return;
}
@@ -2891,6 +2944,14 @@
return;
}
+ const ICData& unary_checks_0 =
+ ICData::ZoneHandle(comp->ic_data()->AsUnaryClassChecks());
+ if (StrictifyEqualityCompareWithICData(
+ comp, unary_checks_0, current_instruction)) {
+ // Based on ICData, equality converted to strict-equality.
+ return;
+ }
+
// Check if ICDData contains checks with Smi/Null combinations. In that case
// we can still emit the optimized Smi equality operation but need to add
// checks for null or Smi.
@@ -2901,8 +2962,6 @@
if (ICDataHasOnlyReceiverArgumentClassIds(ic_data,
smi_or_null,
smi_or_null)) {
- const ICData& unary_checks_0 =
- ICData::ZoneHandle(comp->ic_data()->AsUnaryClassChecks());
AddCheckClass(comp->left()->definition(),
unary_checks_0,
comp->deopt_id(),
@@ -4722,8 +4781,8 @@
if (alloc->ArgumentCount() > 0) {
ASSERT(alloc->ArgumentCount() == 2);
- const Class& cls = Class::Handle(alloc->constructor().Owner());
- intptr_t type_args_offset = cls.type_arguments_field_offset();
+ intptr_t type_args_offset =
+ alloc->cls().type_arguments_field_offset();
if (load->offset_in_bytes() == type_args_offset) {
(*out_values)[load->place_id()] =
alloc->PushArgumentAt(0)->value()->definition();
@@ -6372,6 +6431,11 @@
SetValue(instr, non_constant_);
}
+void ConstantPropagator::VisitFloat32x4TwoArgShuffle(
+ Float32x4TwoArgShuffleInstr* instr) {
+ SetValue(instr, non_constant_);
+}
+
void ConstantPropagator::VisitUint32x4BoolConstructor(
Uint32x4BoolConstructorInstr* instr) {
@@ -7112,7 +7176,7 @@
use != NULL;
use = use->next_use()) {
if (!(use->instruction()->IsStoreInstanceField() &&
- use->use_index() == 0)) {
+ (use->use_index() == 0))) {
return false;
}
}
@@ -7250,6 +7314,7 @@
// present there.
static void AddInstruction(GrowableArray<Instruction*>* exits,
Instruction* exit) {
+ ASSERT(!exit->IsGraphEntry());
for (intptr_t i = 0; i < exits->length(); i++) {
if ((*exits)[i] == exit) {
return;
@@ -7325,10 +7390,9 @@
false, // !static
false, // !final
false, // !const
- Class::Handle(alloc->constructor().Owner()),
+ alloc->cls(),
0)); // No token position.
- const Class& cls = Class::Handle(alloc->constructor().Owner());
- type_args_field.SetOffset(cls.type_arguments_field_offset());
+ type_args_field.SetOffset(alloc->cls().type_arguments_field_offset());
AddField(fields, type_args_field);
}
@@ -7341,9 +7405,8 @@
}
// Insert materializations at environment uses.
- const Class& cls = Class::Handle(alloc->constructor().Owner());
for (intptr_t i = 0; i < exits.length(); i++) {
- CreateMaterializationAt(exits[i], alloc, cls, *fields);
+ CreateMaterializationAt(exits[i], alloc, alloc->cls(), *fields);
}
}
diff --git a/runtime/vm/flow_graph_optimizer.h b/runtime/vm/flow_graph_optimizer.h
index ced6e0f..d92ee29 100644
--- a/runtime/vm/flow_graph_optimizer.h
+++ b/runtime/vm/flow_graph_optimizer.h
@@ -189,6 +189,11 @@
bool StrictifyEqualityCompare(EqualityCompareInstr* compare,
T current_instruction) const;
+ template <typename T>
+ bool StrictifyEqualityCompareWithICData(EqualityCompareInstr* compare,
+ const ICData& unary_ic_data,
+ T current_instruction);
+
void OptimizeLeftShiftBitAndSmiOp(Definition* bit_and_instr,
Definition* left_instr,
Definition* right_instr);
diff --git a/runtime/vm/flow_graph_type_propagator.cc b/runtime/vm/flow_graph_type_propagator.cc
index fd021ff..e20774b 100644
--- a/runtime/vm/flow_graph_type_propagator.cc
+++ b/runtime/vm/flow_graph_type_propagator.cc
@@ -865,8 +865,8 @@
}
-CompileType DropTempsInstr::ComputeType() const {
- return CompileType::Dynamic();
+CompileType* DropTempsInstr::ComputeInitialType() const {
+ return value()->Type();
}
@@ -915,8 +915,14 @@
CompileType AllocateObjectInstr::ComputeType() const {
+ if (!closure_function().IsNull()) {
+ ASSERT(cls().raw() == closure_function().signature_class());
+ return CompileType(CompileType::kNonNullable,
+ cls().id(),
+ &Type::ZoneHandle(cls().SignatureType()));
+ }
// TODO(vegorov): Incorporate type arguments into the returned type.
- return CompileType::FromCid(cid_);
+ return CompileType::FromCid(cls().id());
}
@@ -1082,6 +1088,11 @@
}
+CompileType Float32x4TwoArgShuffleInstr::ComputeType() const {
+ return CompileType::FromCid(kFloat32x4Cid);
+}
+
+
CompileType Uint32x4BoolConstructorInstr::ComputeType() const {
return CompileType::FromCid(kUint32x4Cid);
}
diff --git a/runtime/vm/il_printer.cc b/runtime/vm/il_printer.cc
index 638081c..e396518 100644
--- a/runtime/vm/il_printer.cc
+++ b/runtime/vm/il_printer.cc
@@ -475,7 +475,7 @@
void AllocateObjectInstr::PrintOperandsTo(BufferFormatter* f) const {
- f->Print("%s", Class::Handle(constructor().Owner()).ToCString());
+ f->Print("%s", cls().ToCString());
for (intptr_t i = 0; i < ArgumentCount(); i++) {
f->Print(", ");
PushArgumentAt(i)->value()->PrintTo(f);
@@ -526,11 +526,8 @@
instance()->PrintTo(f);
f->Print(", %"Pd, offset_in_bytes());
- if (field_name_ != NULL) {
- f->Print(" {%s}", field_name_);
- }
-
if (field() != NULL) {
+ f->Print(" {%s}", String::Handle(field()->name()).ToCString());
const char* expected = "?";
if (field()->guarded_cid() != kIllegalCid) {
const Class& cls = Class::Handle(
@@ -706,6 +703,14 @@
}
+void Float32x4TwoArgShuffleInstr::PrintOperandsTo(BufferFormatter* f) const {
+ f->Print("%s, ", MethodRecognizer::KindToCString(op_kind()));
+ left()->PrintTo(f);
+ f->Print(", ");
+ right()->PrintTo(f);
+}
+
+
void Uint32x4BoolConstructorInstr::PrintOperandsTo(BufferFormatter* f) const {
f->Print("Uint32x4.bool(");
value0()->PrintTo(f);
diff --git a/runtime/vm/intermediate_language.h b/runtime/vm/intermediate_language.h
index dc9768c..2492bfa 100644
--- a/runtime/vm/intermediate_language.h
+++ b/runtime/vm/intermediate_language.h
@@ -108,6 +108,11 @@
V(_Float32x4, withZ, Float32x4WithZ, 881355277) \
V(_Float32x4, withW, Float32x4WithW, 441497035) \
V(_Float32x4, _toUint32x4, Float32x4ToUint32x4, 802289205) \
+ V(_Float32x4, withZWInXY, Float32x4WithZWInXY, 465519415) \
+ V(_Float32x4, interleaveXY, Float32x4InterleaveXY, 465519415) \
+ V(_Float32x4, interleaveZW, Float32x4InterleaveZW, 465519415) \
+ V(_Float32x4, interleaveXYPairs, Float32x4InterleaveXYPairs, 465519415) \
+ V(_Float32x4, interleaveZWPairs, Float32x4InterleaveZWPairs, 465519415) \
V(Uint32x4, Uint32x4.bool, Uint32x4BoolConstructor, 487876159) \
V(_Uint32x4, get:flagX, Uint32x4GetFlagX, 782547529) \
V(_Uint32x4, get:flagY, Uint32x4GetFlagY, 782547529) \
@@ -613,6 +618,7 @@
M(Float32x4Clamp) \
M(Float32x4With) \
M(Float32x4ToUint32x4) \
+ M(Float32x4TwoArgShuffle) \
M(MaterializeObject) \
M(Uint32x4BoolConstructor) \
M(Uint32x4GetFlag) \
@@ -899,6 +905,7 @@
friend class Float32x4ClampInstr;
friend class Float32x4WithInstr;
friend class Float32x4ToUint32x4Instr;
+ friend class Float32x4TwoArgShuffleInstr;
friend class Uint32x4BoolConstructorInstr;
friend class Uint32x4GetFlagInstr;
friend class Uint32x4SetFlagInstr;
@@ -3187,7 +3194,7 @@
intptr_t num_temps() const { return num_temps_; }
- virtual CompileType ComputeType() const;
+ virtual CompileType* ComputeInitialType() const;
virtual bool CanDeoptimize() const { return false; }
@@ -3671,12 +3678,15 @@
class AllocateObjectInstr : public TemplateDefinition<0> {
public:
- AllocateObjectInstr(ConstructorCallNode* node,
+ AllocateObjectInstr(intptr_t token_pos,
+ const Class& cls,
ZoneGrowableArray<PushArgumentInstr*>* arguments)
- : ast_node_(*node),
+ : token_pos_(token_pos),
+ cls_(cls),
arguments_(arguments),
- cid_(Class::Handle(node->constructor().Owner()).id()),
- identity_(kUnknown) {
+ identity_(kUnknown),
+ closure_function_(Function::ZoneHandle()),
+ context_field_(Field::ZoneHandle()) {
// Either no arguments or one type-argument and one instantiator.
ASSERT(arguments->is_empty() || (arguments->length() == 2));
}
@@ -3689,8 +3699,18 @@
return (*arguments_)[index];
}
- const Function& constructor() const { return ast_node_.constructor(); }
- intptr_t token_pos() const { return ast_node_.token_pos(); }
+ const Class& cls() const { return cls_; }
+ intptr_t token_pos() const { return token_pos_; }
+
+ const Function& closure_function() const { return closure_function_; }
+ void set_closure_function(const Function& function) {
+ closure_function_ ^= function.raw();
+ }
+
+ const Field& context_field() const { return context_field_; }
+ void set_context_field(const Field& field) {
+ context_field_ ^= field.raw();
+ }
virtual void PrintOperandsTo(BufferFormatter* f) const;
@@ -3713,10 +3733,12 @@
void set_identity(Identity identity) { identity_ = identity; }
private:
- const ConstructorCallNode& ast_node_;
+ const intptr_t token_pos_;
+ const Class& cls_;
ZoneGrowableArray<PushArgumentInstr*>* const arguments_;
- const intptr_t cid_;
Identity identity_;
+ Function& closure_function_;
+ Field& context_field_;
DISALLOW_COPY_AND_ASSIGN(AllocateObjectInstr);
};
@@ -3965,7 +3987,6 @@
result_cid_(kDynamicCid),
immutable_(immutable),
recognized_kind_(MethodRecognizer::kUnknown),
- field_name_(NULL),
field_(NULL) {
ASSERT(type.IsZoneHandle()); // May be null if field is not an instance.
SetInputAt(0, instance);
@@ -3977,9 +3998,6 @@
void set_result_cid(intptr_t value) { result_cid_ = value; }
intptr_t result_cid() const { return result_cid_; }
- void set_field_name(const char* name) { field_name_ = name; }
- const char* field_name() const { return field_name_; }
-
const Field* field() const { return field_; }
void set_field(const Field* field) { field_ = field; }
@@ -4023,7 +4041,6 @@
MethodRecognizer::Kind recognized_kind_;
- const char* field_name_;
const Field* field_;
DISALLOW_COPY_AND_ASSIGN(LoadFieldInstr);
@@ -5512,6 +5529,59 @@
};
+class Float32x4TwoArgShuffleInstr : public TemplateDefinition<2> {
+ public:
+ Float32x4TwoArgShuffleInstr(MethodRecognizer::Kind op_kind, Value* left,
+ Value* right, intptr_t deopt_id)
+ : op_kind_(op_kind) {
+ SetInputAt(0, left);
+ SetInputAt(1, right);
+ deopt_id_ = deopt_id;
+ }
+
+ Value* left() const { return inputs_[0]; }
+ Value* right() const { return inputs_[1]; }
+
+ MethodRecognizer::Kind op_kind() const { return op_kind_; }
+
+ virtual void PrintOperandsTo(BufferFormatter* f) const;
+
+ virtual bool CanDeoptimize() const { return false; }
+
+ virtual Representation representation() const {
+ return kUnboxedFloat32x4;
+ }
+
+ virtual Representation RequiredInputRepresentation(intptr_t idx) const {
+ ASSERT((idx == 0) || (idx == 1));
+ return kUnboxedFloat32x4;
+ }
+
+ virtual intptr_t DeoptimizationTarget() const {
+ // Direct access since this instruction cannot deoptimize, and the deopt-id
+ // was inherited from another instruction that could deoptimize.
+ return deopt_id_;
+ }
+
+ DECLARE_INSTRUCTION(Float32x4TwoArgShuffle)
+ virtual CompileType ComputeType() const;
+
+ virtual bool AllowsCSE() const { return true; }
+ virtual EffectSet Effects() const { return EffectSet::None(); }
+ virtual EffectSet Dependencies() const { return EffectSet::None(); }
+ virtual bool AttributesEqual(Instruction* other) const {
+ return op_kind() == other->AsFloat32x4TwoArgShuffle()->op_kind();
+ }
+
+ virtual bool MayThrow() const { return false; }
+
+ private:
+ const MethodRecognizer::Kind op_kind_;
+
+ DISALLOW_COPY_AND_ASSIGN(Float32x4TwoArgShuffleInstr);
+};
+
+
class Uint32x4SelectInstr : public TemplateDefinition<3> {
public:
Uint32x4SelectInstr(Value* mask, Value* trueValue, Value* falseValue,
diff --git a/runtime/vm/intermediate_language_arm.cc b/runtime/vm/intermediate_language_arm.cc
index dcf9143..dd22a39 100644
--- a/runtime/vm/intermediate_language_arm.cc
+++ b/runtime/vm/intermediate_language_arm.cc
@@ -3341,6 +3341,56 @@
}
+LocationSummary* Float32x4TwoArgShuffleInstr::MakeLocationSummary() const {
+ const intptr_t kNumInputs = 2;
+ const intptr_t kNumTemps = 0;
+ LocationSummary* summary =
+ new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall);
+ summary->set_in(0, Location::RequiresFpuRegister());
+ summary->set_in(1, Location::RequiresFpuRegister());
+ summary->set_out(Location::SameAsFirstInput());
+ return summary;
+}
+
+
+void Float32x4TwoArgShuffleInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
+ QRegister left = locs()->in(0).fpu_reg();
+ QRegister right = locs()->in(1).fpu_reg();
+ QRegister result = locs()->out().fpu_reg();
+
+ ASSERT(result == left);
+
+ DRegister dleft0 = EvenDRegisterOf(left);
+ DRegister dleft1 = OddDRegisterOf(left);
+ DRegister dright0 = EvenDRegisterOf(right);
+ DRegister dright1 = OddDRegisterOf(right);
+
+ switch (op_kind()) {
+ case MethodRecognizer::kFloat32x4WithZWInXY:
+ __ vmovd(dleft0, dright1);
+ break;
+ case MethodRecognizer::kFloat32x4InterleaveXY:
+ __ vmovq(QTMP, right);
+ __ vzipqw(left, QTMP);
+ break;
+ case MethodRecognizer::kFloat32x4InterleaveZW:
+ __ vmovq(QTMP, right);
+ __ vzipqw(left, QTMP);
+ __ vmovq(left, QTMP);
+ break;
+ case MethodRecognizer::kFloat32x4InterleaveXYPairs:
+ __ vmovd(dleft1, dright0);
+ break;
+ case MethodRecognizer::kFloat32x4InterleaveZWPairs:
+ __ vmovq(QTMP, right);
+ __ vmovd(EvenDRegisterOf(QTMP), dleft1);
+ __ vmovq(result, QTMP);
+ break;
+ default: UNREACHABLE();
+ }
+}
+
+
LocationSummary* Uint32x4BoolConstructorInstr::MakeLocationSummary() const {
const intptr_t kNumInputs = 4;
const intptr_t kNumTemps = 1;
@@ -4342,9 +4392,8 @@
void AllocateObjectInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
- const Class& cls = Class::ZoneHandle(constructor().Owner());
- const Code& stub = Code::Handle(StubCode::GetAllocationStubForClass(cls));
- const ExternalLabel label(cls.ToCString(), stub.EntryPoint());
+ const Code& stub = Code::Handle(StubCode::GetAllocationStubForClass(cls()));
+ const ExternalLabel label(cls().ToCString(), stub.EntryPoint());
compiler->GenerateCall(token_pos(),
&label,
PcDescriptors::kOther,
diff --git a/runtime/vm/intermediate_language_ia32.cc b/runtime/vm/intermediate_language_ia32.cc
index fef3d76..b6c0a89 100644
--- a/runtime/vm/intermediate_language_ia32.cc
+++ b/runtime/vm/intermediate_language_ia32.cc
@@ -3371,6 +3371,45 @@
}
+LocationSummary* Float32x4TwoArgShuffleInstr::MakeLocationSummary() const {
+ const intptr_t kNumInputs = 2;
+ const intptr_t kNumTemps = 0;
+ LocationSummary* summary =
+ new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall);
+ summary->set_in(0, Location::RequiresFpuRegister());
+ summary->set_in(1, Location::RequiresFpuRegister());
+ summary->set_out(Location::SameAsFirstInput());
+ return summary;
+}
+
+
+void Float32x4TwoArgShuffleInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
+ XmmRegister left = locs()->in(0).fpu_reg();
+ XmmRegister right = locs()->in(1).fpu_reg();
+
+ ASSERT(locs()->out().fpu_reg() == left);
+
+ switch (op_kind()) {
+ case MethodRecognizer::kFloat32x4WithZWInXY:
+ __ movhlps(left, right);
+ break;
+ case MethodRecognizer::kFloat32x4InterleaveXY:
+ __ unpcklps(left, right);
+ break;
+ case MethodRecognizer::kFloat32x4InterleaveZW:
+ __ unpckhps(left, right);
+ break;
+ case MethodRecognizer::kFloat32x4InterleaveXYPairs:
+ __ unpcklpd(left, right);
+ break;
+ case MethodRecognizer::kFloat32x4InterleaveZWPairs:
+ __ unpckhpd(left, right);
+ break;
+ default: UNREACHABLE();
+ }
+}
+
+
LocationSummary* Uint32x4BoolConstructorInstr::MakeLocationSummary() const {
const intptr_t kNumInputs = 4;
const intptr_t kNumTemps = 0;
@@ -3647,6 +3686,7 @@
summary->set_temp(0, Location::RequiresRegister());
return summary;
}
+
ASSERT(result_cid() == kSmiCid);
const intptr_t kNumInputs = 2;
const intptr_t kNumTemps = 0;
@@ -3707,20 +3747,17 @@
return;
}
- Label done;
ASSERT(result_cid() == kSmiCid);
Register left = locs()->in(0).reg();
Register right = locs()->in(1).reg();
Register result = locs()->out().reg();
__ cmpl(left, right);
+ ASSERT(result == left);
if (is_min) {
- ASSERT(result == left);
- __ j(LESS_EQUAL, &done, Assembler::kNearJump);
+ __ cmovgel(result, right);
} else {
- __ j(GREATER_EQUAL, &done, Assembler::kNearJump);
+ __ cmovlessl(result, right);
}
- __ movl(result, right);
- __ Bind(&done);
}
@@ -4812,9 +4849,8 @@
void AllocateObjectInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
- const Class& cls = Class::ZoneHandle(constructor().Owner());
- const Code& stub = Code::Handle(StubCode::GetAllocationStubForClass(cls));
- const ExternalLabel label(cls.ToCString(), stub.EntryPoint());
+ const Code& stub = Code::Handle(StubCode::GetAllocationStubForClass(cls()));
+ const ExternalLabel label(cls().ToCString(), stub.EntryPoint());
compiler->GenerateCall(token_pos(),
&label,
PcDescriptors::kOther,
diff --git a/runtime/vm/intermediate_language_mips.cc b/runtime/vm/intermediate_language_mips.cc
index 85bf725..7051056 100644
--- a/runtime/vm/intermediate_language_mips.cc
+++ b/runtime/vm/intermediate_language_mips.cc
@@ -2998,6 +2998,17 @@
}
+LocationSummary* Float32x4TwoArgShuffleInstr::MakeLocationSummary() const {
+ UNIMPLEMENTED();
+ return NULL;
+}
+
+
+void Float32x4TwoArgShuffleInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
+ UNIMPLEMENTED();
+}
+
+
LocationSummary* Uint32x4BoolConstructorInstr::MakeLocationSummary() const {
UNIMPLEMENTED();
return NULL;
@@ -3833,9 +3844,8 @@
void AllocateObjectInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
__ TraceSimMsg("AllocateObjectInstr");
__ Comment("AllocateObjectInstr");
- const Class& cls = Class::ZoneHandle(constructor().Owner());
- const Code& stub = Code::Handle(StubCode::GetAllocationStubForClass(cls));
- const ExternalLabel label(cls.ToCString(), stub.EntryPoint());
+ const Code& stub = Code::Handle(StubCode::GetAllocationStubForClass(cls()));
+ const ExternalLabel label(cls().ToCString(), stub.EntryPoint());
compiler->GenerateCall(token_pos(),
&label,
PcDescriptors::kOther,
diff --git a/runtime/vm/intermediate_language_x64.cc b/runtime/vm/intermediate_language_x64.cc
index 3ab4d0f..f93fc93 100644
--- a/runtime/vm/intermediate_language_x64.cc
+++ b/runtime/vm/intermediate_language_x64.cc
@@ -2151,18 +2151,20 @@
}
-static void Emit53BitOverflowCheck(FlowGraphCompiler* compiler,
+static void Emit54BitOverflowCheck(FlowGraphCompiler* compiler,
Label* overflow,
Register result) {
if (FLAG_throw_on_javascript_int_overflow) {
ASSERT(overflow != NULL);
__ movq(TMP, result); // result is a tagged Smi.
- // Bits 54...64 must be all 0 or all 1. (It would be bit 53, but result
+ // Bits 55...64 must be all 0 or all 1. (It would be bit 54, but result
// is tagged.)
- __ shlq(result, Immediate(64 - 54));
- __ sarq(result, Immediate(64 - 54));
+ __ shlq(result, Immediate(64 - 55));
+ __ sarq(result, Immediate(64 - 55));
__ cmpq(result, TMP);
- __ j(NOT_EQUAL, overflow); // 53-bit overflow.
+ __ j(NOT_EQUAL, overflow); // 54-bit overflow.
+ __ cmpq(result, Immediate(-0x1FFFFFFFFFFFFFLL - 1));
+ __ j(EQUAL, overflow); // The most negative 54-bit int is also disallowed.
}
}
@@ -2206,7 +2208,7 @@
// Shift for result now we know there is no overflow.
__ shlq(left, Immediate(value));
}
- Emit53BitOverflowCheck(compiler, deopt, result);
+ Emit54BitOverflowCheck(compiler, deopt, result);
return;
}
@@ -2236,7 +2238,7 @@
__ SmiUntag(right);
__ shlq(left, right);
}
- Emit53BitOverflowCheck(compiler, deopt, result);
+ Emit54BitOverflowCheck(compiler, deopt, result);
return;
}
@@ -2287,7 +2289,7 @@
// Shift for result now we know there is no overflow.
__ shlq(left, right);
}
- Emit53BitOverflowCheck(compiler, deopt, result);
+ Emit54BitOverflowCheck(compiler, deopt, result);
}
@@ -2486,7 +2488,7 @@
UNREACHABLE();
break;
}
- Emit53BitOverflowCheck(compiler, deopt, result);
+ Emit54BitOverflowCheck(compiler, deopt, result);
return;
} // locs()->in(1).IsConstant().
@@ -2529,7 +2531,7 @@
UNREACHABLE();
break;
}
- Emit53BitOverflowCheck(compiler, deopt, result);
+ Emit54BitOverflowCheck(compiler, deopt, result);
return;
} // locs()->in(1).IsStackSlot().
@@ -2659,7 +2661,7 @@
UNREACHABLE();
break;
}
- Emit53BitOverflowCheck(compiler, deopt, result);
+ Emit54BitOverflowCheck(compiler, deopt, result);
}
@@ -3412,6 +3414,45 @@
}
+LocationSummary* Float32x4TwoArgShuffleInstr::MakeLocationSummary() const {
+ const intptr_t kNumInputs = 2;
+ const intptr_t kNumTemps = 0;
+ LocationSummary* summary =
+ new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall);
+ summary->set_in(0, Location::RequiresFpuRegister());
+ summary->set_in(1, Location::RequiresFpuRegister());
+ summary->set_out(Location::SameAsFirstInput());
+ return summary;
+}
+
+
+void Float32x4TwoArgShuffleInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
+ XmmRegister left = locs()->in(0).fpu_reg();
+ XmmRegister right = locs()->in(1).fpu_reg();
+
+ ASSERT(locs()->out().fpu_reg() == left);
+
+ switch (op_kind()) {
+ case MethodRecognizer::kFloat32x4WithZWInXY:
+ __ movhlps(left, right);
+ break;
+ case MethodRecognizer::kFloat32x4InterleaveXY:
+ __ unpcklps(left, right);
+ break;
+ case MethodRecognizer::kFloat32x4InterleaveZW:
+ __ unpckhps(left, right);
+ break;
+ case MethodRecognizer::kFloat32x4InterleaveXYPairs:
+ __ unpcklpd(left, right);
+ break;
+ case MethodRecognizer::kFloat32x4InterleaveZWPairs:
+ __ unpckhpd(left, right);
+ break;
+ default: UNREACHABLE();
+ }
+}
+
+
LocationSummary* Uint32x4BoolConstructorInstr::MakeLocationSummary() const {
const intptr_t kNumInputs = 4;
const intptr_t kNumTemps = 1;
@@ -3775,7 +3816,6 @@
return;
}
- Label done;
ASSERT(result_cid() == kSmiCid);
Register left = locs()->in(0).reg();
Register right = locs()->in(1).reg();
@@ -3783,12 +3823,10 @@
__ cmpq(left, right);
ASSERT(result == left);
if (is_min) {
- __ j(LESS_EQUAL, &done, Assembler::kNearJump);
+ __ cmovgeq(result, right);
} else {
- __ j(GREATER_EQUAL, &done, Assembler::kNearJump);
+ __ cmovlessq(result, right);
}
- __ movq(result, right);
- __ Bind(&done);
}
@@ -3801,7 +3839,7 @@
kDeoptUnaryOp);
__ negq(value);
__ j(OVERFLOW, deopt);
- Emit53BitOverflowCheck(compiler, deopt, value);
+ Emit54BitOverflowCheck(compiler, deopt, value);
break;
}
case Token::kBIT_NOT:
@@ -3862,7 +3900,7 @@
__ shlq(temp, Immediate(1));
__ j(OVERFLOW, &do_call, Assembler::kNearJump);
__ SmiTag(result);
- Emit53BitOverflowCheck(compiler, &do_call, result);
+ Emit54BitOverflowCheck(compiler, &do_call, result);
__ jmp(&done);
__ Bind(&do_call);
ASSERT(instance_call()->HasICData());
@@ -3908,7 +3946,7 @@
__ shlq(temp, Immediate(1));
__ j(OVERFLOW, deopt);
__ SmiTag(result);
- Emit53BitOverflowCheck(compiler, deopt, result);
+ Emit54BitOverflowCheck(compiler, deopt, result);
}
@@ -4485,9 +4523,8 @@
void AllocateObjectInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
- const Class& cls = Class::ZoneHandle(constructor().Owner());
- const Code& stub = Code::Handle(StubCode::GetAllocationStubForClass(cls));
- const ExternalLabel label(cls.ToCString(), stub.EntryPoint());
+ const Code& stub = Code::Handle(StubCode::GetAllocationStubForClass(cls()));
+ const ExternalLabel label(cls().ToCString(), stub.EntryPoint());
compiler->GenerateCall(token_pos(),
&label,
PcDescriptors::kOther,
diff --git a/runtime/vm/native_arguments.h b/runtime/vm/native_arguments.h
index 1027e3f..9be5e0e 100644
--- a/runtime/vm/native_arguments.h
+++ b/runtime/vm/native_arguments.h
@@ -47,8 +47,6 @@
#endif
-void SetReturnValueHelper(Dart_NativeArguments, Dart_Handle);
-
// Class NativeArguments is used to access arguments passed in from
// generated dart code to a runtime function or a dart library native
@@ -158,9 +156,9 @@
class ArgcBits : public BitField<int, kArgcBit, kArgcSize> {};
class InstanceFunctionBit : public BitField<bool, kInstanceFunctionBit, 1> {};
class ClosureFunctionBit : public BitField<bool, kClosureFunctionBit, 1> {};
+ friend class Api;
friend class BootstrapNatives;
friend class Simulator;
- friend void SetReturnValueHelper(Dart_NativeArguments, Dart_Handle);
// Since this function is passed a RawObject directly, we need to be
// exceedingly careful when we use it. If there are any other side
diff --git a/runtime/vm/object.cc b/runtime/vm/object.cc
index dae6510..44d0ea5 100644
--- a/runtime/vm/object.cc
+++ b/runtime/vm/object.cc
@@ -52,7 +52,8 @@
DEFINE_FLAG(int, huge_method_cutoff_in_code_size, 200000,
"Huge method cutoff in unoptimized code size (in bytes).");
DEFINE_FLAG(bool, throw_on_javascript_int_overflow, false,
- "Throw an exception when integer arithmetic exceeds 53 bits.");
+ "Throw an exception when the result of an integer calculation will not "
+ "fit into a javascript integer.");
DECLARE_FLAG(bool, trace_compiler);
DECLARE_FLAG(bool, eliminate_type_checks);
DECLARE_FLAG(bool, enable_type_checks);
@@ -10503,6 +10504,13 @@
}
+void Type::ResetIsFinalized() const {
+ ASSERT(IsFinalized());
+ set_type_state(RawType::kBeingFinalized);
+ SetIsFinalized();
+}
+
+
void Type::set_is_being_finalized() const {
ASSERT(!IsFinalized() && !IsBeingFinalized());
set_type_state(RawType::kBeingFinalized);
@@ -11233,12 +11241,13 @@
}
-// Throw FiftyThreeBitOverflow exception.
-static void ThrowFiftyThreeBitOverflow(const Integer& i) {
+// Throw JavascriptIntegerOverflow exception.
+static void ThrowJavascriptIntegerOverflow(const Integer& i) {
const Array& exc_args = Array::Handle(Array::New(1));
const String& i_str = String::Handle(String::New(i.ToCString()));
exc_args.SetAt(0, i_str);
- Exceptions::ThrowByType(Exceptions::kFiftyThreeBitOverflowError, exc_args);
+ Exceptions::ThrowByType(Exceptions::kJavascriptIntegerOverflowError,
+ exc_args);
}
@@ -11251,7 +11260,7 @@
ASSERT(!BigintOperations::FitsIntoSmi(big));
ASSERT(!BigintOperations::FitsIntoInt64(big));
if (FLAG_throw_on_javascript_int_overflow) {
- ThrowFiftyThreeBitOverflow(big);
+ ThrowJavascriptIntegerOverflow(big);
}
return big.raw();
}
@@ -11260,7 +11269,7 @@
// This is called from LiteralToken::New() in the parser, so we can't
-// raise an exception for 53-bit overflow here. Instead we do it in
+// raise an exception for 54-bit overflow here. Instead we do it in
// Parser::CurrentIntegerLiteral(), which is the point in the parser where
// integer literals escape, so we can call Parser::ErrorMsg().
RawInteger* Integer::NewCanonical(const String& str) {
@@ -11280,13 +11289,23 @@
}
+// dart2js represents integers as double precision floats. It does this using
+// a sign bit and 53 fraction bits. This gives us the range
+// -2^54 - 1 ... 2^54 - 1, i.e. the same as a 54-bit signed integer
+// without the most negative number. Thus, here we check if the value is
+// a 54-bit signed integer and not -2^54
+static bool Is54BitNoMinInt(int64_t value) {
+ return (Utils::IsInt(54, value)) && (value != (-0x1FFFFFFFFFFFFFLL - 1));
+}
+
+
RawInteger* Integer::New(int64_t value, Heap::Space space) {
if ((value <= Smi::kMaxValue) && (value >= Smi::kMinValue)) {
return Smi::New(value);
}
- if (FLAG_throw_on_javascript_int_overflow && !Utils::IsInt(53, value)) {
+ if (FLAG_throw_on_javascript_int_overflow && !Is54BitNoMinInt(value)) {
const Integer &i = Integer::Handle(Mint::New(value));
- ThrowFiftyThreeBitOverflow(i);
+ ThrowJavascriptIntegerOverflow(i);
}
return Mint::New(value, space);
}
@@ -11297,7 +11316,7 @@
if (FLAG_throw_on_javascript_int_overflow) {
const Integer &i =
Integer::Handle(BigintOperations::NewFromUint64(value));
- ThrowFiftyThreeBitOverflow(i);
+ ThrowJavascriptIntegerOverflow(i);
}
return BigintOperations::NewFromUint64(value);
} else {
@@ -11324,8 +11343,9 @@
}
-// Returns true if the signed Integer requires more than 53 bits.
-bool Integer::CheckFiftyThreeBitOverflow() const {
+// Returns true if the signed Integer does not fit into a
+// Javascript (54-bit) integer.
+bool Integer::CheckJavascriptIntegerOverflow() const {
// Always overflow if the value doesn't fit into an int64_t.
int64_t value = 1ULL << 63;
if (IsSmi()) {
@@ -11342,14 +11362,14 @@
value = BigintOperations::ToInt64(big_value);
}
}
- return !Utils::IsInt(53, value);
+ return !Is54BitNoMinInt(value);
}
RawInteger* Integer::AsValidInteger() const {
if (FLAG_throw_on_javascript_int_overflow &&
- CheckFiftyThreeBitOverflow()) {
- ThrowFiftyThreeBitOverflow(*this);
+ CheckJavascriptIntegerOverflow()) {
+ ThrowJavascriptIntegerOverflow(*this);
}
if (IsSmi()) return raw();
if (IsMint()) {
@@ -14360,6 +14380,12 @@
}
+RawTypeParameter* MirrorReference::GetTypeParameterReferent() const {
+ ASSERT(Object::Handle(referent()).IsTypeParameter());
+ return TypeParameter::Cast(Object::Handle(referent())).raw();
+}
+
+
RawMirrorReference* MirrorReference::New(const Object& referent,
Heap::Space space) {
ASSERT(Isolate::Current()->object_store()->mirror_reference_class()
diff --git a/runtime/vm/object.h b/runtime/vm/object.h
index a02cee2..2e0d6c7 100644
--- a/runtime/vm/object.h
+++ b/runtime/vm/object.h
@@ -3821,6 +3821,7 @@
(raw_ptr()->type_state_ == RawType::kFinalizedUninstantiated);
}
void SetIsFinalized() const;
+ void ResetIsFinalized() const; // Ignore current state and set again.
virtual bool IsBeingFinalized() const {
return raw_ptr()->type_state_ == RawType::kBeingFinalized;
}
@@ -4137,8 +4138,8 @@
RawInteger* ArithmeticOp(Token::Kind operation, const Integer& other) const;
RawInteger* BitOp(Token::Kind operation, const Integer& other) const;
- // Returns true if the Integer does not fit in 53 bits.
- bool CheckFiftyThreeBitOverflow() const;
+ // Returns true if the Integer does not fit in a Javascript integer.
+ bool CheckJavascriptIntegerOverflow() const;
private:
// Return an integer in the form of a RawBigint.
@@ -5899,6 +5900,8 @@
RawLibrary* GetLibraryReferent() const;
+ RawTypeParameter* GetTypeParameterReferent() const;
+
static RawMirrorReference* New(const Object& referent,
Heap::Space space = Heap::kNew);
diff --git a/runtime/vm/parser.cc b/runtime/vm/parser.cc
index 11bd5e7..61e184e 100644
--- a/runtime/vm/parser.cc
+++ b/runtime/vm/parser.cc
@@ -29,6 +29,7 @@
DEFINE_FLAG(bool, trace_parser, false, "Trace parser operations.");
DEFINE_FLAG(bool, warning_as_error, false, "Treat warnings as errors.");
DEFINE_FLAG(bool, silent_warnings, false, "Silence warnings.");
+DECLARE_FLAG(bool, error_on_malformed_type);
DECLARE_FLAG(bool, throw_on_javascript_int_overflow);
static void CheckedModeHandler(bool value) {
@@ -378,9 +379,10 @@
RawInteger* ri = Integer::RawCast(literal_token_.value());
if (FLAG_throw_on_javascript_int_overflow) {
const Integer& i = Integer::Handle(ri);
- if (i.CheckFiftyThreeBitOverflow()) {
- ErrorMsg(TokenPos(), "Integer literal does not fit in 53 bits: %s.",
- i.ToCString());
+ if (i.CheckJavascriptIntegerOverflow()) {
+ ErrorMsg(TokenPos(),
+ "Integer literal does not fit in a Javascript integer: %s.",
+ i.ToCString());
}
}
return ri;
@@ -2934,7 +2936,6 @@
Error::Handle(), // No previous error.
current_class(),
type_pos,
- ClassFinalizer::kResolveTypeParameters, // No compile-time error.
"factory '%s' may not redirect to type parameter '%s'",
method->name->ToCString(),
String::Handle(type.UserVisibleName()).ToCString());
@@ -4119,7 +4120,6 @@
RawAbstractTypeArguments* Parser::ParseTypeArguments(
- Error* malformed_error,
ClassFinalizer::FinalizationKind finalization) {
TRACE_PARSER("ParseTypeArguments");
if (CurrentToken() == Token::kLT) {
@@ -4129,14 +4129,8 @@
do {
ConsumeToken();
type = ParseType(finalization);
- // Only keep the error for the first malformed type argument.
- if (malformed_error->IsNull() && type.IsMalformed()) {
- *malformed_error = type.malformed_error();
- }
- // Map a malformed type argument to dynamic, so that malformed types with
- // a resolved type class are handled properly in production mode.
+ // Map a malformed type argument to dynamic.
if (type.IsMalformed()) {
- ASSERT(finalization < ClassFinalizer::kCanonicalizeWellFormed);
type = Type::DynamicType();
}
types.Add(type);
@@ -5375,6 +5369,10 @@
function_type.set_malformed_error(error);
}
+ // The function type was initially marked as instantiated, but it may
+ // actually be uninstantiated.
+ function_type.ResetIsFinalized();
+
// The function variable type should have been patched above.
ASSERT((function_variable == NULL) ||
(function_variable->type().raw() == function_type.raw()));
@@ -6430,10 +6428,8 @@
catch_seen = true;
if (IsLiteral("on")) {
ConsumeToken();
- // TODO(regis): The spec may change in the way a malformed 'on' type is
- // treated. For now, we require the type to be wellformed.
exception_param.type = &AbstractType::ZoneHandle(
- ParseType(ClassFinalizer::kCanonicalizeWellFormed));
+ ParseType(ClassFinalizer::kCanonicalize));
} else {
exception_param.type =
&AbstractType::ZoneHandle(Type::DynamicType());
@@ -7141,13 +7137,15 @@
}
const intptr_t type_pos = TokenPos();
const AbstractType& type = AbstractType::ZoneHandle(
- ParseType(ClassFinalizer::kCanonicalizeExpression));
+ ParseType(ClassFinalizer::kCanonicalize));
if (!type.IsInstantiated() &&
(current_block_->scope->function_level() > 0)) {
// Make sure that the instantiator is captured.
CaptureInstantiator();
}
right_operand = new TypeNode(type_pos, type);
+ // If the type is malformed, it is actually malbounded in checked mode.
+ ASSERT(!type.IsMalformed() || FLAG_enable_type_checks);
if (((op_kind == Token::kIS) || (op_kind == Token::kISNOT)) &&
type.IsMalformed()) {
// Note that a type error is thrown even if the tested value is null
@@ -8159,26 +8157,36 @@
// referenced by a static member.
if (ParsingStaticMember()) {
ASSERT(scope_class.raw() == current_class().raw());
- *type = ClassFinalizer::NewFinalizedMalformedType(
- Error::Handle(), // No previous error.
- scope_class,
- type->token_pos(),
- finalization,
- "type parameter '%s' cannot be referenced "
- "from static member",
- String::Handle(type_parameter.name()).ToCString());
+ if ((finalization == ClassFinalizer::kCanonicalizeWellFormed) ||
+ FLAG_error_on_malformed_type) {
+ *type = ClassFinalizer::NewFinalizedMalformedType(
+ Error::Handle(), // No previous error.
+ scope_class,
+ type->token_pos(),
+ "type parameter '%s' cannot be referenced "
+ "from static member",
+ String::Handle(type_parameter.name()).ToCString());
+ } else {
+ // Map the malformed type to dynamic and ignore type arguments.
+ *type = Type::DynamicType();
+ }
return;
}
// A type parameter cannot be parameterized, so make the type
// malformed if type arguments have previously been parsed.
if (!AbstractTypeArguments::Handle(type->arguments()).IsNull()) {
- *type = ClassFinalizer::NewFinalizedMalformedType(
- Error::Handle(), // No previous error.
- scope_class,
- type_parameter.token_pos(),
- finalization,
- "type parameter '%s' cannot be parameterized",
- String::Handle(type_parameter.name()).ToCString());
+ if ((finalization == ClassFinalizer::kCanonicalizeWellFormed) ||
+ FLAG_error_on_malformed_type) {
+ *type = ClassFinalizer::NewFinalizedMalformedType(
+ Error::Handle(), // No previous error.
+ scope_class,
+ type_parameter.token_pos(),
+ "type parameter '%s' cannot be parameterized",
+ String::Handle(type_parameter.name()).ToCString());
+ } else {
+ // Map the malformed type to dynamic and ignore type arguments.
+ *type = Type::DynamicType();
+ }
return;
}
*type = type_parameter.raw();
@@ -8190,22 +8198,23 @@
if (finalization > ClassFinalizer::kResolveTypeParameters) {
// Resolve classname in the scope of the current library.
Error& error = Error::Handle();
- // If we finalize a type expression, as opposed to a type annotation,
- // we tell the resolver (by passing NULL) to immediately report an
- // ambiguous type as a compile time error.
resolved_type_class = ResolveClassInCurrentLibraryScope(
unresolved_class.token_pos(),
unresolved_class_name,
- finalization >= ClassFinalizer::kCanonicalizeExpression ?
- NULL : &error);
+ &error);
if (!error.IsNull()) {
- *type = ClassFinalizer::NewFinalizedMalformedType(
- error,
- scope_class,
- unresolved_class.token_pos(),
- finalization,
- "cannot resolve class '%s'",
- unresolved_class_name.ToCString());
+ if ((finalization == ClassFinalizer::kCanonicalizeWellFormed) ||
+ FLAG_error_on_malformed_type) {
+ *type = ClassFinalizer::NewFinalizedMalformedType(
+ error,
+ scope_class,
+ unresolved_class.token_pos(),
+ "cannot resolve class '%s'",
+ unresolved_class_name.ToCString());
+ } else {
+ // Map the malformed type to dynamic and ignore type arguments.
+ *type = Type::DynamicType();
+ }
return;
}
}
@@ -8214,39 +8223,46 @@
LibraryPrefix::Handle(unresolved_class.library_prefix());
// Resolve class name in the scope of the library prefix.
Error& error = Error::Handle();
- // If we finalize a type expression, as opposed to a type annotation, we
- // tell the resolver (by passing NULL) to immediately report an ambiguous
- // type as a compile time error.
resolved_type_class = ResolveClassInPrefixScope(
unresolved_class.token_pos(),
lib_prefix,
unresolved_class_name,
- finalization >= ClassFinalizer::kCanonicalizeExpression ?
- NULL : &error);
+ &error);
if (!error.IsNull()) {
- *type = ClassFinalizer::NewFinalizedMalformedType(
- error,
- scope_class,
- unresolved_class.token_pos(),
- finalization,
- "cannot resolve class '%s'",
- unresolved_class_name.ToCString());
+ if ((finalization == ClassFinalizer::kCanonicalizeWellFormed) ||
+ FLAG_error_on_malformed_type) {
+ *type = ClassFinalizer::NewFinalizedMalformedType(
+ error,
+ scope_class,
+ unresolved_class.token_pos(),
+ "cannot resolve class '%s'",
+ unresolved_class_name.ToCString());
+ } else {
+ // Map the malformed type to dynamic and ignore type arguments.
+ *type = Type::DynamicType();
+ }
return;
}
}
// At this point, we can only have a parameterized_type.
- Type& parameterized_type = Type::Handle();
- parameterized_type ^= type->raw();
+ const Type& parameterized_type = Type::Cast(*type);
if (!resolved_type_class.IsNull()) {
// Replace unresolved class with resolved type class.
parameterized_type.set_type_class(resolved_type_class);
} else if (finalization >= ClassFinalizer::kCanonicalize) {
- // The type is malformed.
- ClassFinalizer::FinalizeMalformedType(
- Error::Handle(), // No previous error.
- current_class(), parameterized_type, finalization,
- "type '%s' is not loaded",
- String::Handle(parameterized_type.UserVisibleName()).ToCString());
+ if ((finalization == ClassFinalizer::kCanonicalizeWellFormed) ||
+ FLAG_error_on_malformed_type) {
+ ClassFinalizer::FinalizeMalformedType(
+ Error::Handle(), // No previous error.
+ scope_class,
+ parameterized_type,
+ "type '%s' is not loaded",
+ String::Handle(parameterized_type.UserVisibleName()).ToCString());
+ } else {
+ // Map the malformed type to dynamic and ignore type arguments.
+ *type = Type::DynamicType();
+ }
+ return;
}
}
// Resolve type arguments, if any.
@@ -8954,8 +8970,17 @@
if (!is_top_level_ &&
(type_name.lib_prefix == NULL) &&
ResolveIdentInLocalScope(type_name.ident_pos, *type_name.ident, NULL)) {
- ErrorMsg(type_name.ident_pos, "using '%s' in this context is invalid",
- type_name.ident->ToCString());
+ // The type is malformed. Skip over its type arguments.
+ ParseTypeArguments(ClassFinalizer::kIgnore);
+ if (finalization == ClassFinalizer::kCanonicalizeWellFormed) {
+ return ClassFinalizer::NewFinalizedMalformedType(
+ Error::Handle(), // No previous error.
+ current_class(),
+ type_name.ident_pos,
+ "using '%s' in this context is invalid",
+ type_name.ident->ToCString());
+ }
+ return Type::DynamicType();
}
}
Object& type_class = Object::Handle(isolate());
@@ -8969,27 +8994,13 @@
*type_name.ident,
type_name.ident_pos);
}
- Error& malformed_error = Error::Handle(isolate());
- AbstractTypeArguments& type_arguments =
- AbstractTypeArguments::Handle(isolate(),
- ParseTypeArguments(&malformed_error,
- finalization));
+ AbstractTypeArguments& type_arguments = AbstractTypeArguments::Handle(
+ isolate(), ParseTypeArguments(finalization));
if (finalization == ClassFinalizer::kIgnore) {
return Type::DynamicType();
}
AbstractType& type = AbstractType::Handle(
- isolate(),
- Type::New(type_class, type_arguments, type_name.ident_pos));
- // In production mode, malformed type arguments are mapped to dynamic.
- // In checked mode, a type with malformed type arguments is malformed.
- if (FLAG_enable_type_checks && !malformed_error.IsNull()) {
- Type& parameterized_type = Type::Handle(isolate());
- parameterized_type ^= type.raw();
- parameterized_type.set_type_class(
- Class::Handle(isolate(), Object::dynamic_class()));
- parameterized_type.set_arguments(Object::null_abstract_type_arguments());
- parameterized_type.set_malformed_error(malformed_error);
- }
+ isolate(), Type::New(type_class, type_arguments, type_name.ident_pos));
if (finalization >= ClassFinalizer::kResolveTypeParameters) {
ResolveTypeFromClass(current_class(), finalization, &type);
if (finalization >= ClassFinalizer::kCanonicalize) {
@@ -9031,16 +9042,23 @@
ConsumeToken();
AbstractType& element_type = Type::ZoneHandle(Type::DynamicType());
+ AbstractTypeArguments& list_type_arguments =
+ AbstractTypeArguments::ZoneHandle(type_arguments.raw());
// If no type argument vector is provided, leave it as null, which is
// equivalent to using dynamic as the type argument for the element type.
- if (!type_arguments.IsNull()) {
- ASSERT(type_arguments.Length() > 0);
+ if (!list_type_arguments.IsNull()) {
+ ASSERT(list_type_arguments.Length() > 0);
// List literals take a single type argument.
- element_type = type_arguments.TypeAt(0);
- if (type_arguments.Length() != 1) {
- ErrorMsg(type_pos,
- "a list literal takes one type argument specifying "
- "the element type");
+ if (list_type_arguments.Length() == 1) {
+ element_type = list_type_arguments.TypeAt(0);
+ } else {
+ if (FLAG_error_on_malformed_type) {
+ ErrorMsg(type_pos,
+ "a list literal takes one type argument specifying "
+ "the element type");
+ }
+ // Ignore type arguments.
+ list_type_arguments = AbstractTypeArguments::null();
}
if (is_const && !element_type.IsInstantiated()) {
ErrorMsg(type_pos,
@@ -9048,11 +9066,12 @@
"a type variable");
}
}
- ASSERT(type_arguments.IsNull() || (type_arguments.Length() == 1));
+ ASSERT((list_type_arguments.IsNull() && element_type.IsDynamicType()) ||
+ ((list_type_arguments.Length() == 1) && !element_type.IsNull()));
const Class& array_class = Class::Handle(
isolate()->object_store()->array_class());
Type& type = Type::ZoneHandle(
- Type::New(array_class, type_arguments, type_pos));
+ Type::New(array_class, list_type_arguments, type_pos));
type ^= ClassFinalizer::FinalizeType(
current_class(), type, ClassFinalizer::kCanonicalize);
GrowableArray<AstNode*> element_list;
@@ -9087,7 +9106,7 @@
Array& const_list =
Array::ZoneHandle(Array::New(element_list.length(), Heap::kOld));
const_list.SetTypeArguments(
- AbstractTypeArguments::Handle(type_arguments.Canonicalize()));
+ AbstractTypeArguments::Handle(list_type_arguments.Canonicalize()));
Error& malformed_error = Error::Handle();
for (int i = 0; i < element_list.length(); i++) {
AstNode* elem = element_list[i];
@@ -9124,14 +9143,14 @@
factory_class.LookupFactory(
PrivateCoreLibName(Symbols::ListLiteralFactory())));
ASSERT(!factory_method.IsNull());
- if (!type_arguments.IsNull() &&
- !type_arguments.IsInstantiated() &&
+ if (!list_type_arguments.IsNull() &&
+ !list_type_arguments.IsInstantiated() &&
(current_block_->scope->function_level() > 0)) {
// Make sure that the instantiator is captured.
CaptureInstantiator();
}
AbstractTypeArguments& factory_type_args =
- AbstractTypeArguments::ZoneHandle(type_arguments.raw());
+ AbstractTypeArguments::ZoneHandle(list_type_arguments.raw());
// If the factory class extends other parameterized classes, adjust the
// type argument vector.
if (!factory_type_args.IsNull() && (factory_class.NumTypeArguments() > 1)) {
@@ -9212,49 +9231,72 @@
const intptr_t literal_pos = TokenPos();
ConsumeToken();
+ AbstractType& key_type = Type::ZoneHandle(Type::DynamicType());
AbstractType& value_type = Type::ZoneHandle(Type::DynamicType());
AbstractTypeArguments& map_type_arguments =
AbstractTypeArguments::ZoneHandle(type_arguments.raw());
// If no type argument vector is provided, leave it as null, which is
- // equivalent to using dynamic as the type argument for the value type.
+ // equivalent to using dynamic as the type argument for the both key and value
+ // types.
if (!map_type_arguments.IsNull()) {
ASSERT(map_type_arguments.Length() > 0);
// Map literals take two type arguments.
- if (map_type_arguments.Length() != 2) {
- ErrorMsg(type_pos,
- "a map literal takes two type arguments specifying "
- "the key type and the value type");
- }
- const AbstractType& key_type =
- AbstractType::Handle(map_type_arguments.TypeAt(0));
- value_type = map_type_arguments.TypeAt(1);
- if (!key_type.IsStringType()) {
- ErrorMsg(type_pos, "the key type of a map literal must be 'String'");
- }
- if (is_const && !value_type.IsInstantiated()) {
- ErrorMsg(type_pos,
- "the type argument of a constant map literal cannot include "
- "a type variable");
+ if (map_type_arguments.Length() == 2) {
+ key_type = map_type_arguments.TypeAt(0);
+ value_type = map_type_arguments.TypeAt(1);
+ if (is_const && !type_arguments.IsInstantiated()) {
+ ErrorMsg(type_pos,
+ "the type arguments of a constant map literal cannot include "
+ "a type variable");
+ }
+ if (key_type.IsMalformed()) {
+ if (FLAG_error_on_malformed_type) {
+ ErrorMsg(Error::Handle(key_type.malformed_error()));
+ }
+ // Map malformed key type to dynamic.
+ key_type = Type::DynamicType();
+ map_type_arguments.SetTypeAt(0, key_type);
+ }
+ if (value_type.IsMalformed()) {
+ if (FLAG_error_on_malformed_type) {
+ ErrorMsg(Error::Handle(value_type.malformed_error()));
+ }
+ // Map malformed value type to dynamic.
+ value_type = Type::DynamicType();
+ map_type_arguments.SetTypeAt(1, value_type);
+ }
+ } else {
+ if (FLAG_error_on_malformed_type) {
+ ErrorMsg(type_pos,
+ "a map literal takes two type arguments specifying "
+ "the key type and the value type");
+ }
+ // Ignore type arguments.
+ map_type_arguments = AbstractTypeArguments::null();
}
}
- ASSERT(map_type_arguments.IsNull() || (map_type_arguments.Length() == 2));
+ ASSERT((map_type_arguments.IsNull() &&
+ key_type.IsDynamicType() && value_type.IsDynamicType()) ||
+ ((map_type_arguments.Length() == 2) &&
+ !key_type.IsMalformed() && !value_type.IsMalformed()));
map_type_arguments ^= map_type_arguments.Canonicalize();
GrowableArray<AstNode*> kv_pairs_list;
// Parse the map entries. Note: there may be an optional extra
// comma after the last entry.
while (CurrentToken() != Token::kRBRACE) {
- AstNode* key = NULL;
- if (CurrentToken() == Token::kSTRING) {
- key = ParseStringLiteral();
- }
- if (key == NULL) {
- ErrorMsg("map entry key must be string literal");
- } else if (is_const && !key->IsLiteralNode()) {
- ErrorMsg("map entry key must be compile-time constant string");
+ const bool saved_mode = SetAllowFunctionLiterals(true);
+ const intptr_t key_pos = TokenPos();
+ AstNode* key = ParseExpr(is_const, kConsumeCascades);
+ if (FLAG_enable_type_checks &&
+ !is_const &&
+ !key_type.IsDynamicType()) {
+ key = new AssignableNode(key_pos,
+ key,
+ key_type,
+ Symbols::ListLiteralElement());
}
ExpectToken(Token::kCOLON);
- const bool saved_mode = SetAllowFunctionLiterals(true);
const intptr_t value_pos = TokenPos();
AstNode* value = ParseExpr(is_const, kConsumeCascades);
SetAllowFunctionLiterals(saved_mode);
@@ -9285,27 +9327,38 @@
// First, create the canonicalized key-value pair array.
Array& key_value_array =
Array::ZoneHandle(Array::New(kv_pairs_list.length(), Heap::kOld));
+ AbstractType& arg_type = Type::Handle();
Error& malformed_error = Error::Handle();
for (int i = 0; i < kv_pairs_list.length(); i++) {
AstNode* arg = kv_pairs_list[i];
// Arguments have been evaluated to a literal value already.
ASSERT(arg->IsLiteralNode());
ASSERT(!is_top_level_); // We cannot check unresolved types.
- if (FLAG_enable_type_checks &&
- ((i % 2) == 1) && // Check values only, not keys.
- !value_type.IsDynamicType() &&
- (!arg->AsLiteralNode()->literal().IsNull() &&
- !arg->AsLiteralNode()->literal().IsInstanceOf(
- value_type, TypeArguments::Handle(), &malformed_error))) {
- // If the failure is due to a malformed type error, display it instead.
- if (!malformed_error.IsNull()) {
- ErrorMsg(malformed_error);
+ if (FLAG_enable_type_checks) {
+ if ((i % 2) == 0) {
+ // Check key type.
+ arg_type = key_type.raw();
} else {
- ErrorMsg(arg->AsLiteralNode()->token_pos(),
- "map literal value at index %d must be "
- "a constant of type '%s'",
- i >> 1,
- String::Handle(value_type.UserVisibleName()).ToCString());
+ // Check value type.
+ arg_type = value_type.raw();
+ }
+ if (!arg_type.IsDynamicType() &&
+ (!arg->AsLiteralNode()->literal().IsNull() &&
+ !arg->AsLiteralNode()->literal().IsInstanceOf(
+ arg_type,
+ Object::null_abstract_type_arguments(),
+ &malformed_error))) {
+ // If the failure is due to a malformed type error, display it.
+ if (!malformed_error.IsNull()) {
+ ErrorMsg(malformed_error);
+ } else {
+ ErrorMsg(arg->AsLiteralNode()->token_pos(),
+ "map literal %s at index %d must be "
+ "a constant of type '%s'",
+ ((i % 2) == 0) ? "key" : "value",
+ i >> 1,
+ String::Handle(arg_type.UserVisibleName()).ToCString());
+ }
}
}
key_value_array.SetAt(i, arg->AsLiteralNode()->literal());
@@ -9391,15 +9444,10 @@
ConsumeToken();
}
const intptr_t type_pos = TokenPos();
- Error& malformed_error = Error::Handle();
- AbstractTypeArguments& type_arguments = AbstractTypeArguments::ZoneHandle(
- ParseTypeArguments(&malformed_error,
- ClassFinalizer::kCanonicalizeWellFormed));
+ AbstractTypeArguments& type_arguments = AbstractTypeArguments::Handle(
+ ParseTypeArguments(ClassFinalizer::kCanonicalize));
// Map and List interfaces do not declare bounds on their type parameters, so
- // we should never see a malformed type error here.
- // Note that a bound error is the only possible malformed type error returned
- // when requesting kCanonicalizeWellFormed type finalization.
- ASSERT(malformed_error.IsNull());
+ // we should never see a malformed type argument mapped to dynamic here.
AstNode* primary = NULL;
if ((CurrentToken() == Token::kLBRACK) ||
(CurrentToken() == Token::kINDEX)) {
@@ -9438,7 +9486,7 @@
}
intptr_t type_pos = TokenPos();
AbstractType& type = AbstractType::Handle(
- ParseType(ClassFinalizer::kCanonicalizeExpression));
+ ParseType(ClassFinalizer::kCanonicalizeWellFormed));
// In case the type is malformed, throw a dynamic type error after finishing
// parsing the instance creation expression.
if (!type.IsMalformed() && (type.IsTypeParameter() || type.IsDynamicType())) {
@@ -9447,7 +9495,6 @@
Error::Handle(), // No previous error.
current_class(),
type_pos,
- ClassFinalizer::kResolveTypeParameters, // No compile-time error.
"%s'%s' cannot be instantiated",
type.IsTypeParameter() ? "type parameter " : "",
type.IsTypeParameter() ?
@@ -9455,9 +9502,9 @@
}
// The grammar allows for an optional ('.' identifier)? after the type, which
- // is a named constructor. Note that ParseType(kMustResolve) above will not
- // consume it as part of a misinterpreted qualified identifier, because only a
- // valid library prefix is accepted as qualifier.
+ // is a named constructor. Note that ParseType() above will not consume it as
+ // part of a misinterpreted qualified identifier, because only a valid library
+ // prefix is accepted as qualifier.
String* named_constructor = NULL;
if (CurrentToken() == Token::kPERIOD) {
ConsumeToken();
@@ -9513,7 +9560,6 @@
Error::Handle(), // No previous error.
current_class(),
call_pos,
- ClassFinalizer::kResolveTypeParameters, // No compile-time error.
"class '%s' has no constructor or factory named '%s'",
String::Handle(type_class.Name()).ToCString(),
external_constructor_name.ToCString());
@@ -9633,7 +9679,6 @@
malformed_error,
current_class(),
new_pos,
- ClassFinalizer::kResolveTypeParameters, // No compile-time error.
"const factory result is not an instance of '%s'",
String::Handle(type_bound.UserVisibleName()).ToCString());
new_object = ThrowTypeError(new_pos, type_bound);
diff --git a/runtime/vm/parser.h b/runtime/vm/parser.h
index cca62c0..be417ae 100644
--- a/runtime/vm/parser.h
+++ b/runtime/vm/parser.h
@@ -358,7 +358,6 @@
RawAbstractType* ParseType(ClassFinalizer::FinalizationKind finalization);
void ParseTypeParameters(const Class& cls);
RawAbstractTypeArguments* ParseTypeArguments(
- Error* malformed_error,
ClassFinalizer::FinalizationKind finalization);
void ParseQualIdent(QualIdent* qual_ident);
void ParseMethodOrConstructor(ClassDesc* members, MemberDesc* method);
diff --git a/runtime/vm/simulator_arm.cc b/runtime/vm/simulator_arm.cc
index 760fdfd..3469ab7 100644
--- a/runtime/vm/simulator_arm.cc
+++ b/runtime/vm/simulator_arm.cc
@@ -421,7 +421,11 @@
while (!done) {
if (last_pc != sim_->get_pc()) {
last_pc = sim_->get_pc();
- Disassembler::Disassemble(last_pc, last_pc + Instr::kInstrSize);
+ if (Simulator::IsIllegalAddress(last_pc)) {
+ OS::Print("pc is out of bounds: 0x%"Px"\n", last_pc);
+ } else {
+ Disassembler::Disassemble(last_pc, last_pc + Instr::kInstrSize);
+ }
}
char* line = ReadLine("sim> ");
if (line == NULL) {
@@ -2992,6 +2996,15 @@
}
+static void simd_value_swap(simd_value_t* s1, int i1,
+ simd_value_t* s2, int i2) {
+ uint32_t tmp;
+ tmp = s1->data_[i1].u;
+ s1->data_[i1].u = s2->data_[i2].u;
+ s2->data_[i2].u = tmp;
+}
+
+
void Simulator::DecodeSIMDDataProcessing(Instr* instr) {
ASSERT(instr->ConditionField() == kSpecialCondition);
@@ -3227,6 +3240,20 @@
} else {
UnimplementedInstruction(instr);
}
+ } else if ((instr->Bits(8, 4) == 1) && (instr->Bit(4) == 0) &&
+ (instr->Bits(20, 2) == 3) && (instr->Bits(23, 2) == 3) &&
+ (instr->Bit(7) == 1) && (instr->Bits(16, 4) == 10)) {
+ // Format(instr, "vzipqw 'qd, 'qm");
+ get_qregister(qd, &s8d);
+
+ // Interleave the elements with the low words in qd, and the high words
+ // in qm.
+ simd_value_swap(&s8d, 3, &s8m, 2);
+ simd_value_swap(&s8d, 3, &s8m, 1);
+ simd_value_swap(&s8d, 2, &s8m, 0);
+ simd_value_swap(&s8d, 2, &s8d, 1);
+
+ set_qregister(qm, s8m); // Writes both qd and qm.
} else if ((instr->Bits(8, 4) == 8) && (instr->Bit(4) == 1) &&
(instr->Bits(23, 2) == 2)) {
// Format(instr, "vceqq'sz 'qd, 'qn, 'qm");
diff --git a/runtime/vm/symbols.h b/runtime/vm/symbols.h
index 3345429..9edb6bf 100644
--- a/runtime/vm/symbols.h
+++ b/runtime/vm/symbols.h
@@ -60,6 +60,8 @@
V(StacktraceVar, ":stacktrace_var") \
V(ListLiteralElement, "list literal element") \
V(ForInIter, ":for-in-iter") \
+ V(ClosureFunctionField, ":function") \
+ V(ClosureContextField, ":context") \
V(Library, "library") \
V(Import, "import") \
V(Source, "source") \
@@ -228,7 +230,7 @@
V(NullThrownError, "NullThrownError") \
V(IsolateSpawnException, "IsolateSpawnException") \
V(IsolateUnhandledException, "IsolateUnhandledException") \
- V(FiftyThreeBitOverflowError, "_FiftyThreeBitOverflowError") \
+ V(JavascriptIntegerOverflowError, "_JavascriptIntegerOverflowError") \
V(MirroredCompilationError, "MirroredCompilationError") \
V(MirroredUncaughtExceptionError, "MirroredUncaughtExceptionError") \
V(_setupFullStackTrace, "_setupFullStackTrace") \
@@ -269,9 +271,16 @@
V(_A, "_A") \
V(_stackTrace, "_stackTrace") \
V(_SpecialTypeMirrorImpl, "_SpecialTypeMirrorImpl") \
+ V(_LocalClassMirrorImpl, "_LocalClassMirrorImpl") \
+ V(_LocalFunctionTypeMirrorImpl, "_LocalFunctionTypeMirrorImpl") \
+ V(_LocalLibraryMirrorImpl, "_LocalLibraryMirrorImpl") \
V(_LocalMethodMirrorImpl, "_LocalMethodMirrorImpl") \
V(_LocalVariableMirrorImpl, "_LocalVariableMirrorImpl") \
V(_LocalParameterMirrorImpl, "_LocalParameterMirrorImpl") \
+ V(_LocalIsolateMirrorImpl, "_LocalIsolateMirrorImpl") \
+ V(_LocalMirrorSystemImpl, "_LocalMirrorSystemImpl") \
+ V(_LocalTypedefMirrorImpl, "_LocalTypedefMirrorImpl") \
+ V(_LocalTypeVariableMirrorImpl, "_LocalTypeVariableMirrorImpl") \
// Contains a list of frequently used strings in a canonicalized form. This
diff --git a/sdk/lib/_internal/compiler/implementation/compiler.dart b/sdk/lib/_internal/compiler/implementation/compiler.dart
index 86f5db8..1aa47b7 100644
--- a/sdk/lib/_internal/compiler/implementation/compiler.dart
+++ b/sdk/lib/_internal/compiler/implementation/compiler.dart
@@ -211,6 +211,17 @@
void registerMetadataInstantiatedType(DartType type, TreeElements elements) {}
void registerMetadataStaticUse(Element element) {}
void registerMetadataGetOfStaticFunction(FunctionElement element) {}
+
+ /// Called by [MirrorUsageAnalyzerTask] after it has merged all @MirrorsUsed
+ /// annotations. The arguments corresponds to the unions of the corresponding
+ /// fields of the annotations.
+ void registerMirrorUsage(Set<String> symbols,
+ Set<Element> targets,
+ Set<Element> metaTargets) {}
+
+ /// Returns true if this element should be retained for reflection even if it
+ /// would normally be tree-shaken away.
+ bool isNeededForReflection(Element element) => false;
}
/**
@@ -338,6 +349,9 @@
LibraryElement foreignLibrary;
LibraryElement mainApp;
+ /// Initialized when dart:mirrors is loaded.
+ LibraryElement mirrorsLibrary;
+
ClassElement objectClass;
ClassElement closureClass;
ClassElement boundClosureClass;
@@ -361,6 +375,9 @@
// Initialized when dart:mirrors is loaded.
ClassElement mirrorSystemClass;
+ // Initialized when dart:mirrors is loaded.
+ ClassElement mirrorsUsedClass;
+
// Initialized after mirrorSystemClass has been resolved.
FunctionElement mirrorSystemGetNameFunction;
@@ -437,6 +454,7 @@
EnqueueTask enqueuer;
CompilerTask fileReadingTask;
DeferredLoadTask deferredLoadTask;
+ MirrorUsageAnalyzerTask mirrorUsageAnalyzerTask;
ContainerTracer containerTracer;
String buildId;
@@ -545,6 +563,7 @@
containerTracer = new ContainerTracer(this),
constantHandler = new ConstantHandler(this, backend.constantSystem),
deferredLoadTask = new DeferredLoadTask(this),
+ mirrorUsageAnalyzerTask = new MirrorUsageAnalyzerTask(this),
enqueuer = new EnqueueTask(this)];
tasks.addAll(backend.tasks);
@@ -692,8 +711,11 @@
});
}
if (uri == new Uri(scheme: 'dart', path: 'mirrors')) {
+ mirrorsLibrary = library;
mirrorSystemClass =
findRequiredElement(library, const SourceString('MirrorSystem'));
+ mirrorsUsedClass =
+ findRequiredElement(library, const SourceString('MirrorsUsed'));
} else if (uri == new Uri(scheme: 'dart', path: '_collection-dev')) {
symbolImplementationClass =
findRequiredElement(library, const SourceString('Symbol'));
@@ -898,6 +920,8 @@
});
}
+ mirrorUsageAnalyzerTask.analyzeUsage(mainApp);
+
// In order to see if a library is deferred, we must compute the
// compile-time constants that are metadata. This means adding
// something to the resolution queue. So we cannot wait with
@@ -1181,6 +1205,11 @@
api.Diagnostic.HINT);
}
+ /// For debugging only, print a message with a source location.
+ void reportHere(Spannable node, String debugMessage) {
+ reportInfo(node, MessageKind.GENERIC, {'text': 'HERE: $debugMessage'});
+ }
+
void reportInternalError(Spannable node, String message) {
reportError(
node, MessageKind.GENERIC, {'text': 'Internal Error: $message'});
diff --git a/sdk/lib/_internal/compiler/implementation/constants.dart b/sdk/lib/_internal/compiler/implementation/constants.dart
index 5e3a429..4ff011c 100644
--- a/sdk/lib/_internal/compiler/implementation/constants.dart
+++ b/sdk/lib/_internal/compiler/implementation/constants.dart
@@ -485,4 +485,15 @@
List<Constant> getDependencies() => fields;
accept(ConstantVisitor visitor) => visitor.visitConstructed(this);
+
+ Map<Element, Constant> get fieldElements {
+ // TODO(ahe): Refactor constant system to store this information directly.
+ ClassElement classElement = type.element;
+ int count = 0;
+ Map<Element, Constant> result = new Map<Element, Constant>();
+ classElement.implementation.forEachInstanceField((holder, field) {
+ result[field] = fields[count++];
+ }, includeSuperAndInjectedMembers: true);
+ return result;
+ }
}
diff --git a/sdk/lib/_internal/compiler/implementation/dart2jslib.dart b/sdk/lib/_internal/compiler/implementation/dart2jslib.dart
index c789d11..1af5315 100644
--- a/sdk/lib/_internal/compiler/implementation/dart2jslib.dart
+++ b/sdk/lib/_internal/compiler/implementation/dart2jslib.dart
@@ -32,6 +32,7 @@
import 'js/js.dart' as js;
import 'deferred_load.dart' show DeferredLoadTask;
import 'types/container_tracer.dart' show ContainerTracer;
+import 'mirrors_used.dart' show MirrorUsageAnalyzerTask;
export 'resolution/resolution.dart' show TreeElements, TreeElementMapping;
export 'scanner/scannerlib.dart' show SourceString,
diff --git a/sdk/lib/_internal/compiler/implementation/dart_backend/utils.dart b/sdk/lib/_internal/compiler/implementation/dart_backend/utils.dart
index 4979d19..61bad39 100644
--- a/sdk/lib/_internal/compiler/implementation/dart_backend/utils.dart
+++ b/sdk/lib/_internal/compiler/implementation/dart_backend/utils.dart
@@ -169,11 +169,6 @@
visitReturn(Return node) => new Return(
node.beginToken, node.endToken, visit(node.expression));
- visitScriptTag(ScriptTag node) => new ScriptTag(
- visit(node.tag), visit(node.argument),
- visit(node.prefixIdentifier), visit(node.prefix),
- node.beginToken, node.endToken);
-
visitSend(Send node) => new Send(
visit(node.receiver), visit(node.selector), visit(node.argumentsNode));
diff --git a/sdk/lib/_internal/compiler/implementation/dart_types.dart b/sdk/lib/_internal/compiler/implementation/dart_types.dart
index a3e0821..f490288 100644
--- a/sdk/lib/_internal/compiler/implementation/dart_types.dart
+++ b/sdk/lib/_internal/compiler/implementation/dart_types.dart
@@ -86,21 +86,6 @@
* by the user.
*/
DartType get userProvidedBadType => null;
-
- /// Returns [:true:] if this type contains an ambiguous type.
- bool get containsAmbiguousTypes {
- return !forEachAmbiguousType((_) => false);
- }
-
- /**
- * Calls [f] with each [AmbiguousType] within this type.
- *
- * If [f] returns [: false :], the traversal stops prematurely.
- *
- * [forEachAmbiguousType] returns [: false :] if the traversal was stopped
- * prematurely.
- */
- bool forEachAmbiguousType(bool f(AmbiguousType type)) => true;
/// Is [: true :] if this type has no explict type arguments.
bool get isRaw => true;
@@ -364,14 +349,6 @@
}
}
-class AmbiguousType extends MalformedType {
- AmbiguousType(ErroneousElement element,
- [Link<DartType> typeArguments = null])
- : super(element, null, typeArguments);
-
- bool forEachAmbiguousType(bool f(AmbiguousType type)) => f(this);
-}
-
abstract class GenericType extends DartType {
final Link<DartType> typeArguments;
@@ -401,15 +378,6 @@
return this;
}
- bool forEachAmbiguousType(bool f(AmbiguousType type)) {
- for (DartType typeArgument in typeArguments) {
- if (!typeArgument.forEachAmbiguousType(f)) {
- return false;
- }
- }
- return true;
- }
-
TypeVariableType get typeVariableOccurrence {
return _findTypeVariableOccurrence(typeArguments);
}
@@ -686,28 +654,6 @@
return this;
}
- bool forEachAmbiguousType(bool f(AmbiguousType type)) {
- if (!returnType.forEachAmbiguousType(f)) {
- return false;
- }
- for (DartType parameterType in parameterTypes) {
- if (!parameterType.forEachAmbiguousType(f)) {
- return false;
- }
- }
- for (DartType parameterType in optionalParameterTypes) {
- if (!parameterType.forEachAmbiguousType(f)) {
- return false;
- }
- }
- for (DartType parameterType in namedParameterTypes) {
- if (!parameterType.forEachAmbiguousType(f)) {
- return false;
- }
- }
- return true;
- }
-
DartType unalias(Compiler compiler) => this;
DartType get typeVariableOccurrence {
@@ -1239,23 +1185,6 @@
}
/**
- * Combine error messages in a type containing ambiguous types to a single
- * message string.
- */
- static String fetchReasonsFromAmbiguousType(DartType type) {
- // TODO(johnniwinther): Figure out how to produce good error message in face
- // of multiple errors, and how to ensure non-localized error messages.
- var reasons = new List<String>();
- type.forEachAmbiguousType((AmbiguousType ambiguousType) {
- ErroneousElement error = ambiguousType.element;
- Message message = error.messageKind.message(error.messageArguments);
- reasons.add(message.toString());
- return true;
- });
- return reasons.join(', ');
- }
-
- /**
* Returns the [ClassElement] which declares the type variables occurring in
* [type], or [:null:] if [type] does not contain type variables.
*/
diff --git a/sdk/lib/_internal/compiler/implementation/deferred_load.dart b/sdk/lib/_internal/compiler/implementation/deferred_load.dart
index 7745460..53eca97 100644
--- a/sdk/lib/_internal/compiler/implementation/deferred_load.dart
+++ b/sdk/lib/_internal/compiler/implementation/deferred_load.dart
@@ -194,6 +194,8 @@
Link<LibraryElement> findDeferredLibraries(LibraryElement library) {
Link<LibraryElement> link = const Link<LibraryElement>();
for (LibraryTag tag in library.tags) {
+ // TODO(ahe): This iterates over parts and exports as well, but should
+ // only iterate over imports.
Link<MetadataAnnotation> metadata = tag.metadata;
if (metadata == null) continue;
for (MetadataAnnotation metadata in tag.metadata) {
diff --git a/sdk/lib/_internal/compiler/implementation/elements/elements.dart b/sdk/lib/_internal/compiler/implementation/elements/elements.dart
index 6413fc1..30825c7 100644
--- a/sdk/lib/_internal/compiler/implementation/elements/elements.dart
+++ b/sdk/lib/_internal/compiler/implementation/elements/elements.dart
@@ -119,8 +119,6 @@
const ElementKind('ambiguous', ElementCategory.NONE);
static const ElementKind ERROR =
const ElementKind('error', ElementCategory.NONE);
- static const ElementKind MALFORMED_TYPE =
- const ElementKind('malformed', ElementCategory.NONE);
toString() => id;
}
diff --git a/sdk/lib/_internal/compiler/implementation/elements/modelx.dart b/sdk/lib/_internal/compiler/implementation/elements/modelx.dart
index 57b7c7b..6c8bdd1 100644
--- a/sdk/lib/_internal/compiler/implementation/elements/modelx.dart
+++ b/sdk/lib/_internal/compiler/implementation/elements/modelx.dart
@@ -795,8 +795,8 @@
bool hasLibraryName() => libraryTag != null;
/**
- * Returns the library name (as defined by the #library tag) or for script
- * (which have no #library tag) the script file name. The latter case is used
+ * Returns the library name (as defined by the library tag) or for script
+ * (which have no library tag) the script file name. The latter case is used
* to private 'library name' for scripts to use for instance in dartdoc.
*/
String getLibraryOrScriptName() {
diff --git a/sdk/lib/_internal/compiler/implementation/enqueue.dart b/sdk/lib/_internal/compiler/implementation/enqueue.dart
index 353897d..288065d 100644
--- a/sdk/lib/_internal/compiler/implementation/enqueue.dart
+++ b/sdk/lib/_internal/compiler/implementation/enqueue.dart
@@ -114,20 +114,16 @@
void internalAddToWorkList(Element element);
void registerInstantiatedType(InterfaceType type, TreeElements elements) {
- ClassElement cls = type.element;
- elements.registerDependency(cls);
- cls.ensureResolved(compiler);
- universe.instantiatedTypes.add(type);
- if (universe.instantiatedClasses.contains(cls)) return;
- if (!cls.isAbstract(compiler)) {
- universe.instantiatedClasses.add(cls);
- }
- onRegisterInstantiatedClass(cls);
- // We only tell the backend once that [cls] was instantiated, so
- // any additional dependencies must be treated as global
- // dependencies.
- compiler.backend.registerInstantiatedClass(
- cls, this, compiler.globalDependencies);
+ task.measure(() {
+ ClassElement cls = type.element;
+ elements.registerDependency(cls);
+ cls.ensureResolved(compiler);
+ universe.instantiatedTypes.add(type);
+ if (!cls.isAbstract(compiler)) {
+ universe.instantiatedClasses.add(cls);
+ }
+ onRegisterInstantiatedClass(cls);
+ });
}
void registerInstantiatedClass(ClassElement cls, TreeElements elements) {
@@ -254,6 +250,7 @@
void onRegisterInstantiatedClass(ClassElement cls) {
task.measure(() {
+ if (seenClasses.contains(cls)) return;
// The class must be resolved to compute the set of all
// supertypes.
cls.ensureResolved(compiler);
@@ -267,6 +264,11 @@
if (isResolutionQueue) {
compiler.resolver.checkClass(cls);
}
+ // We only tell the backend once that [cls] was instantiated, so
+ // any additional dependencies must be treated as global
+ // dependencies.
+ compiler.backend.registerInstantiatedClass(
+ cls, this, compiler.globalDependencies);
}
processClass(cls);
for (Link<DartType> supertypes = cls.allSupertypes;
@@ -311,6 +313,7 @@
}
void pretendElementWasUsed(Element element, TreeElements elements) {
+ if (!compiler.backend.isNeededForReflection(element)) return;
if (Elements.isUnresolved(element)) {
// Ignore.
} else if (element.isSynthesized
diff --git a/sdk/lib/_internal/compiler/implementation/js_backend/backend.dart b/sdk/lib/_internal/compiler/implementation/js_backend/backend.dart
index 99b1dae..cc7b0fb 100644
--- a/sdk/lib/_internal/compiler/implementation/js_backend/backend.dart
+++ b/sdk/lib/_internal/compiler/implementation/js_backend/backend.dart
@@ -105,23 +105,6 @@
}
}
-class AmbiguousTypeCheckedModeHelper extends CheckedModeHelper {
- const AmbiguousTypeCheckedModeHelper(SourceString name) : super(name);
-
- void generateAdditionalArguments(SsaCodeGenerator codegen,
- HTypeConversion node,
- List<jsAst.Expression> arguments) {
- DartType type = node.typeExpression;
- assert(type.containsAmbiguousTypes);
- String reasons = Types.fetchReasonsFromAmbiguousType(type);
-
- arguments.add(js.string(quote('$type')));
- arguments.add(js.string(quote(reasons)));
- }
-
- String quote(String string) => string.replaceAll('"', r'\"');
-}
-
/*
* Invariants:
* canInline(function) implies canInline(function, insideLoop:true)
@@ -337,6 +320,16 @@
/// preserved, these elements must be compiled.
final List<FunctionElement> metadataGetOfStaticFunction = <FunctionElement>[];
+ /// List of symbols that the user has requested for reflection.
+ final Set<String> symbolsUsed = new Set<String>();
+
+ /// List of elements that the user has requested for reflection.
+ final Set<Element> targetsUsed = new Set<Element>();
+
+ /// List of annotations provided by user that indicate that the annotated
+ /// element must be retained.
+ final Set<Element> metaTargetsUsed = new Set<Element>();
+
JavaScriptBackend(Compiler compiler, bool generateSourceMap, bool disableEval)
: namer = determineNamer(compiler),
oneShotInterceptors = new Map<String, Selector>(),
@@ -853,13 +846,6 @@
// We also need the native variant of the check (for DOM types).
helper = getNativeCheckedModeHelper(type, typeCast: false);
if (helper != null) world.addToWorkList(helper.getElement(compiler));
- if (type.containsAmbiguousTypes) {
- enqueueInResolution(getThrowMalformedSubtypeError(), elements);
- return;
- }
- } else if (type.containsAmbiguousTypes) {
- registerThrowRuntimeError(elements);
- return;
}
bool isTypeVariable = type.kind == TypeKind.TYPE_VARIABLE;
if (!type.isRaw || type.containsTypeVariables) {
@@ -1120,16 +1106,7 @@
Element element = type.element;
bool nativeCheck = nativeCheckOnly ||
emitter.nativeEmitter.requiresNativeIsCheck(element);
- if (type.containsAmbiguousTypes) {
- // Check for malformed types first, because the type may be a list type
- // with a malformed argument type.
- if (nativeCheckOnly) return null;
- return typeCast
- ? const AmbiguousTypeCheckedModeHelper(
- const SourceString('malformedTypeCast'))
- : const AmbiguousTypeCheckedModeHelper(
- const SourceString('malformedTypeCheck'));
- } else if (type == compiler.types.voidType) {
+ if (type == compiler.types.voidType) {
assert(!typeCast); // Cannot cast to void.
if (nativeCheckOnly) return null;
return const CheckedModeHelper(const SourceString('voidTypeCheck'));
@@ -1255,11 +1232,6 @@
return compiler.findHelper(const SourceString('throwRuntimeError'));
}
- Element getThrowMalformedSubtypeError() {
- return compiler.findHelper(
- const SourceString('throwMalformedSubtypeError'));
- }
-
Element getThrowAbstractClassInstantiationError() {
return compiler.findHelper(
const SourceString('throwAbstractClassInstantiationError'));
@@ -1484,6 +1456,26 @@
metadataGetOfStaticFunction.add(element);
}
}
+
+ void registerMirrorUsage(Set<String> symbols,
+ Set<Element> targets,
+ Set<Element> metaTargets) {
+ if (symbols != null) symbolsUsed.addAll(symbols);
+ if (targets != null) {
+ for (Element element in targets) {
+ // TODO(ahe): Implement finer granularity.
+ targetsUsed.add(element.getLibrary());
+ }
+ }
+ if (metaTargets != null) metaTargetsUsed.addAll(metaTargets);
+ }
+
+ bool isNeededForReflection(Element element) {
+ // TODO(ahe): Implement this.
+ if (!metaTargetsUsed.isEmpty) return true;
+ if (targetsUsed.contains(element.getLibrary())) return true;
+ return false;
+ }
}
/// Records that [type] is used by [user.element].
diff --git a/sdk/lib/_internal/compiler/implementation/js_backend/emitter.dart b/sdk/lib/_internal/compiler/implementation/js_backend/emitter.dart
index 2ee81e7..2302aec 100644
--- a/sdk/lib/_internal/compiler/implementation/js_backend/emitter.dart
+++ b/sdk/lib/_internal/compiler/implementation/js_backend/emitter.dart
@@ -726,7 +726,7 @@
])),
js('var constructor = defineClass(name, cls, fields, desc)'),
- optional(backend.hasRetainedMetadata,
+ optional(backend.isTreeShakingDisabled,
js('constructor["${namer.metadataField}"] = desc')),
js('isolateProperties[cls] = constructor'),
js.if_('supr', js('pendingClasses[cls] = supr'))
diff --git a/sdk/lib/_internal/compiler/implementation/js_backend/namer.dart b/sdk/lib/_internal/compiler/implementation/js_backend/namer.dart
index 92a4898..796718a 100644
--- a/sdk/lib/_internal/compiler/implementation/js_backend/namer.dart
+++ b/sdk/lib/_internal/compiler/implementation/js_backend/namer.dart
@@ -724,8 +724,7 @@
kind == ElementKind.GETTER ||
kind == ElementKind.SETTER ||
kind == ElementKind.TYPEDEF ||
- kind == ElementKind.LIBRARY ||
- kind == ElementKind.MALFORMED_TYPE) {
+ kind == ElementKind.LIBRARY) {
bool fixedName = false;
if (kind == ElementKind.CLASS) {
ClassElement classElement = element;
diff --git a/sdk/lib/_internal/compiler/implementation/mirrors/dart2js_mirror.dart b/sdk/lib/_internal/compiler/implementation/mirrors/dart2js_mirror.dart
index a00716e..2910563 100644
--- a/sdk/lib/_internal/compiler/implementation/mirrors/dart2js_mirror.dart
+++ b/sdk/lib/_internal/compiler/implementation/mirrors/dart2js_mirror.dart
@@ -531,8 +531,8 @@
LibraryMirror library() => this;
/**
- * Returns the library name (for libraries with a #library tag) or the script
- * file name (for scripts without a #library tag). The latter case is used to
+ * Returns the library name (for libraries with a library tag) or the script
+ * file name (for scripts without a library tag). The latter case is used to
* provide a 'library name' for scripts, to use for instance in dartdoc.
*/
String get simpleName {
diff --git a/sdk/lib/_internal/compiler/implementation/mirrors_used.dart b/sdk/lib/_internal/compiler/implementation/mirrors_used.dart
new file mode 100644
index 0000000..7b795a2
--- /dev/null
+++ b/sdk/lib/_internal/compiler/implementation/mirrors_used.dart
@@ -0,0 +1,391 @@
+// Copyright (c) 2013, 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 dart2js.mirrors_used;
+
+import 'dart2jslib.dart' show
+ Compiler,
+ CompilerTask,
+ Constant,
+ ConstructedConstant,
+ ListConstant,
+ MessageKind,
+ SourceString,
+ StringConstant,
+ TypeConstant;
+
+import 'elements/elements.dart' show
+ Element,
+ LibraryElement,
+ MetadataAnnotation,
+ VariableElement;
+
+import 'util/util.dart' show
+ Link;
+
+import 'dart_types.dart' show
+ DartType;
+
+import 'tree/tree.dart' show
+ Import,
+ LibraryTag;
+
+/**
+ * Compiler task that analyzes MirrorsUsed annotations.
+ *
+ * When importing 'dart:mirrors', it is possible to annotate the import with
+ * MirrorsUsed annotation. This is a way to declare what elements will be
+ * reflected on at runtime. Such elements, even they would normally be
+ * discarded by the implicit tree-shaking algorithm must be preserved in the
+ * final output.
+ *
+ * Since some libraries cannot tell exactly what they will be reflecting on, it
+ * is possible for one library to specify a MirrorsUsed annotation that applies
+ * to another library. For example:
+ *
+ * Mirror utility library that cannot tell what it is reflecting on:
+ * library mirror_utils;
+ * import 'dart:mirrors';
+ * ...
+ *
+ * The main app which knows how it use the mirror utility library:
+ * library main_app;
+ * @MirrorsUsed(override='mirror_utils')
+ * import 'dart:mirrors';
+ * import 'mirror_utils.dart';
+ * ...
+ *
+ * In this case, we say that @MirrorsUsed in main_app overrides @MirrorsUsed in
+ * mirror_utils.
+ *
+ * It is possible to override all libraries using override='*'. If multiple
+ * catch-all overrides like this, they are merged together.
+ *
+ * It is possible for library "a" to declare that it overrides library "b", and
+ * vice versa. In this case, both annotations will be discarded and the
+ * compiler will emit a hint (that is, a warning that is not specified by the
+ * language specification).
+ *
+ * After applying all the overrides, we can iterate over libraries that import
+ * 'dart:mirrors'. If a library does not have an associated MirrorsUsed
+ * annotation, then we have to discard all MirrorsUsed annotations and assume
+ * everything can be reflected on.
+ *
+ * On the other hand, if all libraries importing dart:mirrors have a
+ * MirrorsUsed annotation, these annotations are merged.
+ *
+ * MERGING MIRRORSUSED
+ *
+ * TBD.
+ */
+class MirrorUsageAnalyzerTask extends CompilerTask {
+ Set<LibraryElement> librariesWithUsage;
+
+ MirrorUsageAnalyzerTask(Compiler compiler)
+ : super(compiler);
+
+ void analyzeUsage(LibraryElement mainApp) {
+ if (compiler.mirrorsLibrary == null) return;
+ MirrorUsageAnalyzer analyzer = new MirrorUsageAnalyzer(compiler, this);
+ measure(analyzer.run);
+ List<String> symbols = analyzer.mergedMirrorUsage.symbols;
+ List<Element> targets = analyzer.mergedMirrorUsage.targets;
+ List<Element> metaTargets = analyzer.mergedMirrorUsage.metaTargets;
+ compiler.backend.registerMirrorUsage(
+ symbols == null ? null : new Set<String>.from(symbols),
+ targets == null ? null : new Set<Element>.from(targets),
+ metaTargets == null ? null : new Set<Element>.from(metaTargets));
+ librariesWithUsage = analyzer.librariesWithUsage;
+ }
+
+ bool hasMirrorUsage(Element element) {
+ return librariesWithUsage != null
+ && librariesWithUsage.contains(element.getLibrary());
+ }
+}
+
+class MirrorUsageAnalyzer {
+ final Compiler compiler;
+ final MirrorUsageAnalyzerTask task;
+ final List<LibraryElement> wildcard;
+ final Set<LibraryElement> librariesWithUsage;
+ final Set<LibraryElement> librariesWithoutUsage;
+ MirrorUsage mergedMirrorUsage;
+
+ MirrorUsageAnalyzer(Compiler compiler, this.task)
+ : compiler = compiler,
+ wildcard = compiler.libraries.values.toList(),
+ librariesWithUsage = new Set<LibraryElement>(),
+ librariesWithoutUsage = new Set<LibraryElement>();
+
+ void run() {
+ Map<LibraryElement, List<MirrorUsage>> usageMap =
+ collectMirrorsUsedAnnotation();
+ propagateOverrides(usageMap);
+ librariesWithoutUsage.removeAll(usageMap.keys);
+ if (librariesWithoutUsage.isEmpty) {
+ mergedMirrorUsage = mergeUsages(usageMap);
+ } else {
+ mergedMirrorUsage = new MirrorUsage(null, wildcard, null, null);
+ }
+ }
+
+ Map<LibraryElement, List<MirrorUsage>> collectMirrorsUsedAnnotation() {
+ Map<LibraryElement, List<MirrorUsage>> result =
+ new Map<LibraryElement, List<MirrorUsage>>();
+ for (LibraryElement library in compiler.libraries.values) {
+ if (library.isInternalLibrary) continue;
+ librariesWithoutUsage.add(library);
+ for (LibraryTag tag in library.tags) {
+ Import importTag = tag.asImport();
+ if (importTag == null) continue;
+ compiler.withCurrentElement(library, () {
+ List<MirrorUsage> usages =
+ mirrorsUsedOnLibraryTag(library, importTag);
+ if (usages != null) {
+ List<MirrorUsage> existing = result[library];
+ if (existing != null) {
+ existing.addAll(usages);
+ } else {
+ result[library] = usages;
+ }
+ }
+ });
+ }
+ }
+ return result;
+ }
+
+ void propagateOverrides(Map<LibraryElement, List<MirrorUsage>> usageMap) {
+ Map<LibraryElement, List<MirrorUsage>> propagatedOverrides =
+ new Map<LibraryElement, List<MirrorUsage>>();
+ usageMap.forEach((LibraryElement library, List<MirrorUsage> usages) {
+ for (MirrorUsage usage in usages) {
+ List<Element> override = usage.override;
+ if (override == null) continue;
+ if (override == wildcard) {
+ for (LibraryElement overridden in wildcard) {
+ if (overridden != library) {
+ List<MirrorUsage> overriddenUsages = propagatedOverrides
+ .putIfAbsent(overridden, () => <MirrorUsage>[]);
+ overriddenUsages.add(usage);
+ }
+ }
+ } else {
+ for (Element overridden in override) {
+ List<MirrorUsage> overriddenUsages = propagatedOverrides
+ .putIfAbsent(overridden, () => <MirrorUsage>[]);
+ overriddenUsages.add(usage);
+ }
+ }
+ }
+ });
+ propagatedOverrides.forEach((LibraryElement overridden,
+ List<MirrorUsage> overriddenUsages) {
+ List<MirrorUsage> usages =
+ usageMap.putIfAbsent(overridden, () => <MirrorUsage>[]);
+ usages.addAll(overriddenUsages);
+ });
+ }
+
+ List<MirrorUsage> mirrorsUsedOnLibraryTag(LibraryElement library,
+ Import tag) {
+ LibraryElement importedLibrary = library.getLibraryFromTag(tag);
+ if (importedLibrary != compiler.mirrorsLibrary) {
+ return null;
+ }
+ List<MirrorUsage> result = <MirrorUsage>[];
+ for (MetadataAnnotation metadata in tag.metadata) {
+ metadata.ensureResolved(compiler);
+ Element element = metadata.value.computeType(compiler).element;
+ if (element == compiler.mirrorsUsedClass) {
+ try {
+ MirrorUsage usage =
+ new MirrorUsageBuilder(this, library).build(metadata.value);
+ result.add(usage);
+ } on BadMirrorsUsedAnnotation catch (e) {
+ compiler.reportError(
+ metadata, MessageKind.GENERIC, {'text': e.message});
+ }
+ }
+ }
+ return result;
+ }
+
+ MirrorUsage mergeUsages(Map<LibraryElement, List<MirrorUsage>> usageMap) {
+ Set<MirrorUsage> usagesToMerge = new Set<MirrorUsage>();
+ usageMap.forEach((LibraryElement library, List<MirrorUsage> usages) {
+ librariesWithUsage.add(library);
+ usagesToMerge.addAll(usages);
+ });
+ if (usagesToMerge.isEmpty) {
+ return new MirrorUsage(null, wildcard, null, null);
+ } else {
+ MirrorUsage result = new MirrorUsage(null, null, null, null);
+ for (MirrorUsage usage in usagesToMerge) {
+ result = merge(result, usage);
+ }
+ return result;
+ }
+ }
+
+ MirrorUsage merge(MirrorUsage a, MirrorUsage b) {
+ if (a.symbols == null && a.targets == null && a.metaTargets == null) {
+ return b;
+ } else if (
+ b.symbols == null && b.targets == null && b.metaTargets == null) {
+ return a;
+ }
+ // TODO(ahe): Test the following cases.
+ List<String> symbols = a.symbols;
+ if (symbols == null) {
+ symbols = b.symbols;
+ } else if (b.symbols != null) {
+ symbols.addAll(b.symbols);
+ }
+ List<Element> targets = a.targets;
+ if (targets == null) {
+ targets = b.targets;
+ } else if (targets != wildcard && b.targets != null) {
+ targets.addAll(b.targets);
+ }
+ List<Element> metaTargets = a.metaTargets;
+ if (metaTargets == null) {
+ metaTargets = b.metaTargets;
+ } else if (metaTargets != wildcard && b.metaTargets != null) {
+ metaTargets.addAll(b.metaTargets);
+ }
+ return new MirrorUsage(symbols, targets, metaTargets, null);
+ }
+}
+
+class MirrorUsage {
+ final List<String> symbols;
+ final List<Element> targets;
+ final List<Element> metaTargets;
+ final List<Element> override;
+
+ MirrorUsage(this.symbols, this.targets, this.metaTargets, this.override);
+
+ String toString() {
+ return
+ 'MirrorUsage('
+ 'symbols = $symbols, '
+ 'targets = $targets, '
+ 'metaTargets = $metaTargets, '
+ 'override = $override'
+ ')';
+
+ }
+}
+
+class MirrorUsageBuilder {
+ MirrorUsageAnalyzer analyzer;
+ LibraryElement enclosingLibrary;
+
+ MirrorUsageBuilder(this.analyzer, this.enclosingLibrary);
+
+ Compiler get compiler => analyzer.compiler;
+
+ MirrorUsage build(ConstructedConstant constant) {
+ Map<Element, Constant> fields = constant.fieldElements;
+ VariableElement symbolsField = compiler.mirrorsUsedClass.lookupLocalMember(
+ const SourceString('symbols'));
+ VariableElement targetsField = compiler.mirrorsUsedClass.lookupLocalMember(
+ const SourceString('targets'));
+ VariableElement metaTargetsField =
+ compiler.mirrorsUsedClass.lookupLocalMember(
+ const SourceString('metaTargets'));
+ VariableElement overrideField = compiler.mirrorsUsedClass.lookupLocalMember(
+ const SourceString('override'));
+ List<String> symbols =
+ convertToListOfStrings(
+ convertConstantToUsageList(fields[symbolsField]));
+ List<Element> targets =
+ resolveUsageList(convertConstantToUsageList(fields[targetsField]));
+
+ List<Element> metaTargets =
+ resolveUsageList(convertConstantToUsageList(fields[metaTargetsField]));
+ List<Element> override =
+ resolveUsageList(convertConstantToUsageList(fields[overrideField]));
+ return new MirrorUsage(symbols, targets, metaTargets, override);
+ }
+
+ List convertConstantToUsageList(Constant constant) {
+ if (constant.isNull()) {
+ return null;
+ } else if (constant.isList()) {
+ ListConstant list = constant;
+ List result = [];
+ for (Constant entry in list.entries) {
+ if (entry.isString()) {
+ StringConstant string = entry;
+ result.add(string.value.slowToString());
+ } else if (entry.isType()) {
+ TypeConstant type = entry;
+ result.add(type.representedType);
+ } else {
+ throw new BadMirrorsUsedAnnotation(
+ 'Expected a string or type, but got "$entry".');
+ }
+ }
+ return result;
+ } else if (constant.isType()) {
+ TypeConstant type = constant;
+ return [type.representedType];
+ } else if (constant.isString()) {
+ StringConstant string = constant;
+ return
+ string.value.slowToString().split(',').map((e) => e.trim()).toList();
+ } else {
+ throw new BadMirrorsUsedAnnotation(
+ 'Expected a string or a list of string, but got "$constant".');
+ }
+ }
+
+ List<String> convertToListOfStrings(List list) {
+ if (list == null) return null;
+ List<String> result = new List<String>(list.length);
+ int count = 0;
+ for (var entry in list) {
+ if (entry is! String) {
+ throw new BadMirrorsUsedAnnotation(
+ 'Expected a string, but got "$entry"');
+ }
+ result[count++] = entry;
+ }
+ return result;
+ }
+
+ List<Element> resolveUsageList(List list) {
+ if (list == null) return null;
+ if (list.length == 1 && list[0] == '*') {
+ return analyzer.wildcard;
+ }
+ List<Element> result = <Element>[];
+ for (var entry in list) {
+ if (entry is DartType) {
+ DartType type = entry;
+ result.add(type.element);
+ } else {
+ String string = entry;
+ for (LibraryElement l in compiler.libraries.values) {
+ if (l.hasLibraryName()) {
+ String libraryName = l.getLibraryOrScriptName();
+ if (string == libraryName || string.startsWith('$libraryName.')) {
+ result.add(l);
+ break;
+ }
+ }
+ }
+ }
+ }
+ return result;
+ }
+}
+
+class BadMirrorsUsedAnnotation {
+ final String message;
+ BadMirrorsUsedAnnotation(this.message);
+}
diff --git a/sdk/lib/_internal/compiler/implementation/resolution/members.dart b/sdk/lib/_internal/compiler/implementation/resolution/members.dart
index cea260d..607bc6e 100644
--- a/sdk/lib/_internal/compiler/implementation/resolution/members.dart
+++ b/sdk/lib/_internal/compiler/implementation/resolution/members.dart
@@ -1428,8 +1428,7 @@
}
DartType resolveTypeAnnotation(MappingVisitor visitor, TypeAnnotation node,
- {bool malformedIsError: false,
- bool ambiguousIsError: false}) {
+ {bool malformedIsError: false}) {
Identifier typeName;
SourceString prefixName;
Send send = node.typeName.asSend();
@@ -1446,10 +1445,8 @@
DartType reportFailureAndCreateType(DualKind messageKind,
Map messageArguments,
- {DartType userProvidedBadType,
- bool isError: false,
- bool isAmbiguous: false}) {
- if (isError) {
+ {DartType userProvidedBadType}) {
+ if (malformedIsError) {
visitor.error(node, messageKind.error, messageArguments);
} else {
visitor.warning(node, messageKind.warning, messageArguments);
@@ -1459,9 +1456,7 @@
visitor.enclosingElement);
var arguments = new LinkBuilder<DartType>();
resolveTypeArguments(visitor, node, null, arguments);
- return isAmbiguous
- ? new AmbiguousType(erroneousElement, arguments.toLink())
- : new MalformedType(erroneousElement,
+ return new MalformedType(erroneousElement,
userProvidedBadType, arguments.toLink());
}
@@ -1480,18 +1475,15 @@
if (element == null) {
type = reportFailureAndCreateType(
- MessageKind.CANNOT_RESOLVE_TYPE, {'typeName': node.typeName},
- isError: malformedIsError);
+ MessageKind.CANNOT_RESOLVE_TYPE, {'typeName': node.typeName});
} else if (element.isAmbiguous()) {
AmbiguousElement ambiguous = element;
type = reportFailureAndCreateType(
- ambiguous.messageKind, ambiguous.messageArguments,
- isError: ambiguousIsError, isAmbiguous: true);
+ ambiguous.messageKind, ambiguous.messageArguments);
ambiguous.diagnose(visitor.mapping.currentElement, compiler);
} else if (!element.impliesType()) {
type = reportFailureAndCreateType(
- MessageKind.NOT_A_TYPE, {'node': node.typeName},
- isError: malformedIsError);
+ MessageKind.NOT_A_TYPE, {'node': node.typeName});
} else {
if (identical(element, compiler.types.voidType.element) ||
identical(element, compiler.dynamicClass)) {
@@ -1545,8 +1537,7 @@
type = reportFailureAndCreateType(
MessageKind.TYPE_VARIABLE_WITHIN_STATIC_MEMBER,
{'typeVariableName': node},
- userProvidedBadType: element.computeType(compiler),
- isError: malformedIsError);
+ userProvidedBadType: element.computeType(compiler));
} else {
type = element.computeType(compiler);
}
@@ -1570,8 +1561,7 @@
MappingVisitor visitor,
TypeAnnotation node,
Link<DartType> typeVariables,
- LinkBuilder<DartType> arguments,
- {bool ambiguousIsError: false}) {
+ LinkBuilder<DartType> arguments) {
if (node.typeArguments == null) {
return false;
}
@@ -1584,8 +1574,7 @@
typeArguments.head, MessageKind.ADDITIONAL_TYPE_ARGUMENT.warning);
typeArgumentCountMismatch = true;
}
- DartType argType = resolveTypeAnnotation(visitor, typeArguments.head,
- ambiguousIsError: ambiguousIsError);
+ DartType argType = resolveTypeAnnotation(visitor, typeArguments.head);
arguments.addLast(argType);
if (typeVariables != null && !typeVariables.isEmpty) {
typeVariables = typeVariables.tail;
@@ -2228,7 +2217,9 @@
Element target = resolveSend(node);
sendIsMemberAccess = oldSendIsMemberAccess;
- if (target != null && target == compiler.mirrorSystemGetNameFunction) {
+ if (target != null
+ && target == compiler.mirrorSystemGetNameFunction
+ && !compiler.mirrorUsageAnalyzerTask.hasMirrorUsage(enclosingElement)) {
compiler.reportHint(
node.selector, MessageKind.STATIC_FUNCTION_BLOAT,
{'class': compiler.mirrorSystemClass.name,
@@ -2646,9 +2637,12 @@
}
}
} else {
- compiler.reportHint(
- node.newToken, MessageKind.NON_CONST_BLOAT,
- {'name': compiler.symbolClass.name});
+ if (!compiler.mirrorUsageAnalyzerTask.hasMirrorUsage(
+ enclosingElement)) {
+ compiler.reportHint(
+ node.newToken, MessageKind.NON_CONST_BLOAT,
+ {'name': compiler.symbolClass.name});
+ }
world.registerNewSymbol(mapping);
}
}
@@ -2686,13 +2680,11 @@
}
DartType resolveTypeExpression(TypeAnnotation node) {
- return resolveTypeAnnotation(node, isTypeExpression: true);
+ return resolveTypeAnnotation(node);
}
- DartType resolveTypeAnnotation(TypeAnnotation node,
- {bool isTypeExpression: false}) {
- DartType type = typeResolver.resolveTypeAnnotation(
- this, node, ambiguousIsError: isTypeExpression);
+ DartType resolveTypeAnnotation(TypeAnnotation node) {
+ DartType type = typeResolver.resolveTypeAnnotation(this, node);
if (type == null) return null;
if (inCheckContext) {
compiler.enqueuer.resolution.registerIsCheck(type, mapping);
diff --git a/sdk/lib/_internal/compiler/implementation/scanner/listener.dart b/sdk/lib/_internal/compiler/implementation/scanner/listener.dart
index 5c69c08..65f35e2 100644
--- a/sdk/lib/_internal/compiler/implementation/scanner/listener.dart
+++ b/sdk/lib/_internal/compiler/implementation/scanner/listener.dart
@@ -287,12 +287,6 @@
Token beginToken, Token endToken) {
}
- void beginScriptTag(Token token) {
- }
-
- void endScriptTag(bool hasPrefix, Token beginToken, Token endToken) {
- }
-
void beginSend(Token token) {
}
@@ -729,26 +723,6 @@
compilationUnitElement.setPartOf(tag, listener);
}
- void endScriptTag(bool hasPrefix, Token beginToken, Token endToken) {
- LiteralString prefix = null;
- Identifier argumentName = null;
- if (hasPrefix) {
- prefix = popLiteralString();
- argumentName = popNode();
- }
- LiteralString firstArgument = popLiteralString();
- Identifier tag = popNode();
- ScriptTag scriptTag = new ScriptTag(tag, firstArgument, argumentName,
- prefix, beginToken, endToken);
- if (const SourceString('import') == tag.source ||
- const SourceString('source') == tag.source ||
- const SourceString('library') == tag.source) {
- addScriptTag(scriptTag);
- } else {
- recoverableError('unknown tag: ${tag.source.slowToString()}', node: tag);
- }
- }
-
void endMetadata(Token beginToken, Token periodBeforeName, Token endToken) {
if (periodBeforeName != null) {
popNode(); // Discard name.
@@ -1041,12 +1015,6 @@
metadata = metadata.prepend(annotation);
}
- // TODO(ahe): Remove this method.
- void addScriptTag(ScriptTag tag) {
- listener.onDeprecatedFeature(tag, '# tags');
- addLibraryTag(tag.toLibraryTag());
- }
-
void addLibraryTag(LibraryTag tag) {
if (!allowLibraryTags()) {
recoverableError('library tags not allowed here', node: tag);
diff --git a/sdk/lib/_internal/compiler/implementation/scanner/parser.dart b/sdk/lib/_internal/compiler/implementation/scanner/parser.dart
index 78329cc..ee84b4c 100644
--- a/sdk/lib/_internal/compiler/implementation/scanner/parser.dart
+++ b/sdk/lib/_internal/compiler/implementation/scanner/parser.dart
@@ -52,8 +52,6 @@
return parseClass(token);
} else if (identical(value, 'typedef')) {
return parseTypedef(token);
- } else if (identical(value, '#')) {
- return parseScriptTags(token);
} else if (identical(value, 'library')) {
return parseLibraryName(token);
} else if (identical(value, 'import')) {
@@ -747,24 +745,6 @@
return token;
}
- Token parseScriptTags(Token token) {
- Token begin = token;
- listener.beginScriptTag(token);
- token = parseIdentifier(token.next);
- token = expect('(', token);
- token = parseLiteralStringOrRecoverExpression(token);
- bool hasPrefix = false;
- if (optional(',', token)) {
- hasPrefix = true;
- token = parseIdentifier(token.next);
- token = expect(':', token);
- token = parseLiteralStringOrRecoverExpression(token);
- }
- token = expect(')', token);
- listener.endScriptTag(hasPrefix, begin, token);
- return expectSemicolon(token);
- }
-
Token parseLiteralStringOrRecoverExpression(Token token) {
if (identical(token.kind, STRING_TOKEN)) {
return parseLiteralString(token);
diff --git a/sdk/lib/_internal/compiler/implementation/ssa/builder.dart b/sdk/lib/_internal/compiler/implementation/ssa/builder.dart
index 151efbd..12be2f6 100644
--- a/sdk/lib/_internal/compiler/implementation/ssa/builder.dart
+++ b/sdk/lib/_internal/compiler/implementation/ssa/builder.dart
@@ -2770,21 +2770,12 @@
bool isNot = node.isIsNotCheck;
DartType type = elements.getType(node.typeAnnotationFromIsCheckOrCast);
type = type.unalias(compiler);
- if (type.containsAmbiguousTypes) {
- String reasons = Types.fetchReasonsFromAmbiguousType(type);
- if (compiler.enableTypeAssertions) {
- generateMalformedSubtypeError(node, expression, type, reasons);
- } else {
- generateRuntimeError(node, '$type is ambiguous: $reasons');
- }
- } else {
- HInstruction instruction = buildIsNode(node, type, expression);
- if (isNot) {
- add(instruction);
- instruction = new HNot(instruction);
- }
- push(instruction);
+ HInstruction instruction = buildIsNode(node, type, expression);
+ if (isNot) {
+ add(instruction);
+ instruction = new HNot(instruction);
}
+ push(instruction);
}
HLiteralList buildTypeVariableList(ClassElement contextClass) {
@@ -3409,11 +3400,6 @@
}
}
- /**
- * Documentation wanted -- johnniwinther
- *
- * Invariant: [argument] must not be malformed in checked mode.
- */
HInstruction analyzeTypeArgument(DartType argument) {
if (argument.treatAsDynamic) {
// Represent [dynamic] as [null].
@@ -3464,11 +3450,6 @@
pop();
}
- /**
- * Documentation wanted -- johnniwinther
- *
- * Invariant: [type] must not be malformed in checked mode.
- */
handleNewSend(NewExpression node, InterfaceType type) {
Send send = node.send;
bool isListConstructor = false;
@@ -3745,14 +3726,6 @@
existingArguments: existingArguments);
}
- void generateMalformedSubtypeError(Node node, HInstruction value,
- DartType type, String reasons) {
- HInstruction typeString = addConstantString(node, type.toString());
- HInstruction reasonsString = addConstantString(node, reasons);
- Element helper = backend.getThrowMalformedSubtypeError();
- pushInvokeStatic(node, helper, [value, typeString, reasonsString]);
- }
-
visitNewExpression(NewExpression node) {
Element element = elements[node.send];
final bool isSymbolConstructor = element == compiler.symbolConstructor;
@@ -3782,16 +3755,9 @@
}
} else {
DartType type = elements.getType(node);
- if (compiler.enableTypeAssertions && type.containsAmbiguousTypes) {
- String reasons = Types.fetchReasonsFromAmbiguousType(type);
- // TODO(johnniwinther): Change to resemble type errors from bounds check
- // on type arguments.
- generateRuntimeError(node, '$type is malformed: $reasons');
- } else {
- // TODO(karlklose): move this type registration to the codegen.
- compiler.codegenWorld.instantiatedTypes.add(type);
- handleNewSend(node, type);
- }
+ // TODO(karlklose): move this type registration to the codegen.
+ compiler.codegenWorld.instantiatedTypes.add(type);
+ handleNewSend(node, type);
}
}
@@ -4952,21 +4918,6 @@
void visitThen() {
CatchBlock catchBlock = link.head;
link = link.tail;
-
- if (compiler.enableTypeAssertions) {
- // In checked mode: throw a type error if the on-catch type is
- // malformed.
- if (catchBlock.onKeyword != null) {
- DartType type = elements.getType(catchBlock.type);
- if (type != null && type.containsAmbiguousTypes) {
- String reasons = Types.fetchReasonsFromAmbiguousType(type);
- generateMalformedSubtypeError(node,
- unwrappedException, type, reasons);
- pop();
- return;
- }
- }
- }
if (catchBlock.exception != null) {
localsHandler.updateLocal(elements[catchBlock.exception],
unwrappedException);
@@ -5076,10 +5027,6 @@
inTryStatement = oldInTryStatement;
}
- visitScriptTag(ScriptTag node) {
- compiler.unimplemented('SsaBuilder.visitScriptTag', node: node);
- }
-
visitCatchBlock(CatchBlock node) {
visit(node.block);
}
diff --git a/sdk/lib/_internal/compiler/implementation/ssa/nodes.dart b/sdk/lib/_internal/compiler/implementation/ssa/nodes.dart
index 38e9e4f..a580f24 100644
--- a/sdk/lib/_internal/compiler/implementation/ssa/nodes.dart
+++ b/sdk/lib/_internal/compiler/implementation/ssa/nodes.dart
@@ -1117,9 +1117,6 @@
// available.
assert(type.kind != TypeKind.TYPE_VARIABLE);
assert(type.isRaw || type.kind == TypeKind.FUNCTION);
- if (type.containsAmbiguousTypes) {
- return new HTypeConversion(type, kind, HType.UNKNOWN, this);
- }
if (type.treatAsDynamic) return this;
if (identical(type.element, compiler.objectClass)) return this;
if (type.kind != TypeKind.INTERFACE) {
diff --git a/sdk/lib/_internal/compiler/implementation/tree/nodes.dart b/sdk/lib/_internal/compiler/implementation/tree/nodes.dart
index d0d94a4..210ebe5 100644
--- a/sdk/lib/_internal/compiler/implementation/tree/nodes.dart
+++ b/sdk/lib/_internal/compiler/implementation/tree/nodes.dart
@@ -66,7 +66,6 @@
R visitPrefix(Prefix node) => visitNodeList(node);
R visitRethrow(Rethrow node) => visitStatement(node);
R visitReturn(Return node) => visitStatement(node);
- R visitScriptTag(ScriptTag node) => visitNode(node);
R visitSend(Send node) => visitExpression(node);
R visitSendSet(SendSet node) => visitSend(node);
R visitStatement(Statement node) => visitNode(node);
@@ -181,7 +180,6 @@
PartOf asPartOf() => null;
Rethrow asRethrow() => null;
Return asReturn() => null;
- ScriptTag asScriptTag() => null;
Send asSend() => null;
SendSet asSendSet() => null;
Statement asStatement() => null;
@@ -1695,59 +1693,6 @@
Node getBody() => statement;
}
-class ScriptTag extends Node {
- final Identifier tag;
- final StringNode argument;
- final Identifier prefixIdentifier;
- final StringNode prefix;
-
- final Token beginToken;
- final Token endToken;
-
- ScriptTag(this.tag, this.argument, this.prefixIdentifier, this.prefix,
- this.beginToken, this.endToken);
-
- bool isImport() => tag.source == const SourceString("import");
- bool isSource() => tag.source == const SourceString("source");
- bool isLibrary() => tag.source == const SourceString("library");
-
- ScriptTag asScriptTag() => this;
-
- accept(Visitor visitor) => visitor.visitScriptTag(this);
-
- visitChildren(Visitor visitor) {
- tag.accept(visitor);
- argument.accept(visitor);
- if (prefixIdentifier != null) prefixIdentifier.accept(visitor);
- if (prefix != null) prefix.accept(visitor);
- }
-
- Token getBeginToken() => beginToken;
-
- Token getEndToken() => endToken;
-
- LibraryTag toLibraryTag() {
- if (isImport()) {
- Identifier prefixNode;
- if (prefix != null) {
- SourceString source = prefix.dartString.source;
- Token prefixToken = prefix.getBeginToken();
- Token token = new StringToken.fromSource(IDENTIFIER_INFO, source,
- prefixToken.charOffset);
- token.next = prefixToken.next;
- prefixNode = new Identifier(token);
- }
- return new Import(tag.token, argument, prefixNode, null, null);
- } else if (isLibrary()) {
- return new LibraryName(tag.token, argument, null);
- } else if (isSource()) {
- return new Part(tag.token, argument, null);
- } else {
- throw 'Unknown script tag ${tag.token.slowToString()}';
- }
- }
-}
-
abstract class LibraryTag extends Node {
final Link<MetadataAnnotation> metadata;
diff --git a/sdk/lib/_internal/compiler/implementation/tree/prettyprint.dart b/sdk/lib/_internal/compiler/implementation/tree/prettyprint.dart
index 6d85e08..60f4807 100644
--- a/sdk/lib/_internal/compiler/implementation/tree/prettyprint.dart
+++ b/sdk/lib/_internal/compiler/implementation/tree/prettyprint.dart
@@ -314,10 +314,6 @@
closeNode();
}
- visitScriptTag(ScriptTag node) {
- visitNodeWithChildren(node, "ScriptTag");
- }
-
visitChildNode(Node node, String fieldName) {
if (node == null) return;
addCurrentIndent();
diff --git a/sdk/lib/_internal/compiler/implementation/tree/unparser.dart b/sdk/lib/_internal/compiler/implementation/tree/unparser.dart
index 274117b..92d10e3 100644
--- a/sdk/lib/_internal/compiler/implementation/tree/unparser.dart
+++ b/sdk/lib/_internal/compiler/implementation/tree/unparser.dart
@@ -477,20 +477,6 @@
sb.write('import "$uri"$suffix;');
}
- visitScriptTag(ScriptTag node) {
- add(node.beginToken.value);
- visit(node.tag);
- sb.write('(');
- visit(node.argument);
- if (node.prefixIdentifier != null) {
- visit(node.prefixIdentifier);
- sb.write(':');
- visit(node.prefix);
- }
- sb.write(')');
- add(node.endToken.value);
- }
-
visitTryStatement(TryStatement node) {
addToken(node.tryKeyword);
visit(node.tryBlock);
diff --git a/sdk/lib/_internal/compiler/implementation/types/concrete_types_inferrer.dart b/sdk/lib/_internal/compiler/implementation/types/concrete_types_inferrer.dart
index 57b7904..ab7226b 100644
--- a/sdk/lib/_internal/compiler/implementation/types/concrete_types_inferrer.dart
+++ b/sdk/lib/_internal/compiler/implementation/types/concrete_types_inferrer.dart
@@ -2165,10 +2165,6 @@
inferrer.fail(node, 'not yet implemented');
}
- ConcreteType visitScriptTag(ScriptTag node) {
- inferrer.fail(node, 'not yet implemented');
- }
-
ConcreteType visitCatchBlock(CatchBlock node) {
inferrer.fail(node, 'not yet implemented');
}
diff --git a/sdk/lib/_internal/lib/io_patch.dart b/sdk/lib/_internal/lib/io_patch.dart
index c077360..d5e55c6 100644
--- a/sdk/lib/_internal/lib/io_patch.dart
+++ b/sdk/lib/_internal/lib/io_patch.dart
@@ -277,6 +277,11 @@
bool useBuiltinRoots: true}) {
throw new UnsupportedError("SecureSocket.initialize");
}
+
+ patch static X509Certificate addCertificate(List<int> certificate,
+ String trust) {
+ throw new UnsupportedError("SecureSocket.addCertificate");
+ }
}
patch class _SecureFilter {
diff --git a/sdk/lib/_internal/lib/js_helper.dart b/sdk/lib/_internal/lib/js_helper.dart
index 5f590b0..0efd6c2 100644
--- a/sdk/lib/_internal/lib/js_helper.dart
+++ b/sdk/lib/_internal/lib/js_helper.dart
@@ -802,14 +802,6 @@
throw new RuntimeError(message);
}
-/**
- * The SSA builder generates a call to this method when a malformed type is used
- * in a subtype test.
- */
-throwMalformedSubtypeError(value, type, reasons) {
- throw new TypeErrorImplementation.malformedSubtype(value, type, reasons);
-}
-
throwAbstractClassInstantiationError(className) {
throw new AbstractClassInstantiationError(className);
}
@@ -1801,16 +1793,6 @@
throw new TypeErrorImplementation(value, 'void');
}
-malformedTypeCheck(value, type, reasons) {
- if (value == null) return value;
- throwMalformedSubtypeError(value, type, reasons);
-}
-
-malformedTypeCast(value, type, reasons) {
- if (value == null) return value;
- throw new CastErrorImplementation.malformedTypeCast(value, type, reasons);
-}
-
/**
* Special interface recognized by the compiler and implemented by DOM
* objects that support integer indexing. This interface is not
@@ -1833,14 +1815,6 @@
: message = "type '${Primitives.objectTypeName(value)}' is not a subtype "
"of type '$type'";
- /**
- * Type error caused by a subtype test on a malformed type.
- */
- TypeErrorImplementation.malformedSubtype(Object value,
- String type, String reasons)
- : message = "type '${Primitives.objectTypeName(value)}' is not a subtype "
- "of type '$type' because '$type' is malformed: $reasons.";
-
String toString() => message;
}
@@ -1856,17 +1830,6 @@
: message = "CastError: Casting value of type $actualType to"
" incompatible type $expectedType";
-
- /**
- * Cast error caused by a type cast to a malformed type.
- */
- CastErrorImplementation.malformedTypeCast(Object value,
- String type, String reasons)
- : message = "CastError: Type '${Primitives.objectTypeName(value)}' "
- "cannot be cast to type '$type' because '$type' is "
- "malformed: $reasons.";
-
-
String toString() => message;
}
diff --git a/sdk/lib/_internal/pub/lib/src/command.dart b/sdk/lib/_internal/pub/lib/src/command.dart
index 8e3f9b5..97ad11ce 100644
--- a/sdk/lib/_internal/pub/lib/src/command.dart
+++ b/sdk/lib/_internal/pub/lib/src/command.dart
@@ -15,6 +15,7 @@
import 'command/help.dart';
import 'command/install.dart';
import 'command/lish.dart';
+import 'command/serve.dart';
import 'command/update.dart';
import 'command/uploader.dart';
import 'command/version.dart';
@@ -193,6 +194,7 @@
'help': new HelpCommand(),
'install': new InstallCommand(),
'publish': new LishCommand(),
+ 'serve': new ServeCommand(),
'update': new UpdateCommand(),
'uploader': new UploaderCommand(),
'version': new VersionCommand()
diff --git a/sdk/lib/_internal/pub/lib/src/command/serve.dart b/sdk/lib/_internal/pub/lib/src/command/serve.dart
new file mode 100644
index 0000000..ce8db31
--- /dev/null
+++ b/sdk/lib/_internal/pub/lib/src/command/serve.dart
@@ -0,0 +1,172 @@
+// Copyright (c) 2013, 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 pub.command.serve;
+
+import 'dart:async';
+import 'dart:io';
+
+import 'package:barback/barback.dart';
+import 'package:path/path.dart' as path;
+
+import '../command.dart';
+import '../entrypoint.dart';
+import '../exit_codes.dart' as exit_codes;
+import '../log.dart' as log;
+import '../pub_package_provider.dart';
+import '../utils.dart';
+
+final _green = getPlatformString('\u001b[32m');
+final _red = getPlatformString('\u001b[31m');
+final _none = getPlatformString('\u001b[0m');
+
+/// Handles the `serve` pub command.
+class ServeCommand extends PubCommand {
+ String get description => "Run a local web development server.";
+ String get usage => 'pub serve';
+
+ ServeCommand() {
+ commandParser.addOption('port', defaultsTo: '8080',
+ help: 'The port to listen on.');
+ }
+
+ Future onRun() {
+ // The completer for the top-level future returned by the command. Only
+ // used to keep pub running (by not completing) and to pipe fatal errors
+ // to pub's top-level error-handling machinery.
+ var completer = new Completer();
+
+ return new Future.value().then((_) {
+ // The server relies on an up-to-date lockfile, so install first if
+ // needed.
+ if (!entrypoint.isLockFileUpToDate()) {
+ log.message("Dependencies have changed, installing...");
+ return entrypoint.installDependencies().then((_) {
+ log.message("Dependencies installed!");
+ });
+ }
+ }).then((_) {
+ return PubPackageProvider.create(entrypoint);
+ }).then((provider) {
+ var port;
+ try {
+ port = int.parse(commandOptions['port']);
+ } on FormatException catch(_) {
+ log.error('Could not parse port "${commandOptions['port']}"');
+ this.printUsage();
+ exit(exit_codes.USAGE);
+ }
+
+ var barback = new Barback(provider);
+
+ barback.results.listen((result) {
+ if (result.succeeded) {
+ // TODO(rnystrom): Report using growl/inotify-send where available.
+ log.message("Build completed ${_green}successfully$_none");
+ } else {
+ log.message("Build completed with "
+ "${_red}${result.errors.length}$_none errors.");
+ }
+ });
+
+ barback.errors.listen((error) {
+ log.error("${_red}Build error:\n$error$_none");
+ });
+
+ // TODO(rnystrom): Watch file system and update sources again when they
+ // are added or modified.
+
+ HttpServer.bind("localhost", port).then((server) {
+ log.message("Serving ${entrypoint.root.name} "
+ "on http://localhost:${server.port}");
+
+ // Add all of the visible files.
+ for (var package in provider.packages) {
+ barback.updateSources(provider.listAssets(package));
+ }
+
+ server.listen((request) {
+ var id = getIdFromUri(request.uri);
+ if (id == null) {
+ return notFound(request, "Path ${request.uri.path} is not valid.");
+ }
+
+ barback.getAssetById(id).then((asset) {
+ log.message(
+ "$_green${request.method}$_none ${request.uri} -> $asset");
+ // TODO(rnystrom): Set content-type based on asset type.
+ return request.response.addStream(asset.read()).then((_) {
+ request.response.close();
+ });
+ // TODO(rnystrom): Serve up a 500 if we get an error reading the
+ // asset.
+ }).catchError((error) {
+ log.error("$_red${request.method}$_none ${request.uri} -> $error");
+ if (error is! AssetNotFoundException) {
+ completer.completeError(error);
+ return;
+ }
+
+ notFound(request, error);
+ });
+ });
+ });
+
+ return completer.future;
+ });
+ }
+
+ /// Responds to [request] with a 404 response and closes it.
+ void notFound(HttpRequest request, message) {
+ request.response.statusCode = 404;
+ request.response.reasonPhrase = "Not Found";
+ request.response.write(message);
+ request.response.close();
+ }
+
+ AssetId getIdFromUri(Uri uri) {
+ var parts = path.url.split(uri.path);
+
+ // Strip the leading "/" from the URL.
+ parts.removeAt(0);
+
+ var isSpecial = false;
+
+ // Checks to see if [uri]'s path contains a special directory [name] that
+ // identifies an asset within some package. If so, maps the package name
+ // and path following that to be within [dir] inside that package.
+ AssetId _trySpecialUrl(String name, String dir) {
+ // Find the package name and the relative path in the package.
+ var index = parts.indexOf(name);
+ if (index == -1) return null;
+
+ // If we got here, the path *did* contain the special directory, which
+ // means we should not interpret it as a regular path, even if it's
+ // missing the package name after it, which makes it invalid here.
+ isSpecial = true;
+ if (index + 1 >= parts.length) return null;
+
+ var package = parts[index + 1];
+ var assetPath = path.url.join(dir,
+ path.url.joinAll(parts.skip(index + 2)));
+ return new AssetId(package, assetPath);
+ }
+
+ // See if it's "packages" URL.
+ var id = _trySpecialUrl("packages", "lib");
+ if (id != null) return id;
+
+ // See if it's an "assets" URL.
+ id = _trySpecialUrl("assets", "asset");
+ if (id != null) return id;
+
+ // If we got here, we had a path like "/packages" which is a special
+ // directory, but not a valid path since it lacks a following package name.
+ if (isSpecial) return null;
+
+ // Otherwise, it's a path in current package's web directory.
+ return new AssetId(entrypoint.root.name,
+ path.url.join("web", path.url.joinAll(parts)));
+ }
+}
diff --git a/sdk/lib/_internal/pub/lib/src/entrypoint.dart b/sdk/lib/_internal/pub/lib/src/entrypoint.dart
index 1f09a3a..70888bc 100644
--- a/sdk/lib/_internal/pub/lib/src/entrypoint.dart
+++ b/sdk/lib/_internal/pub/lib/src/entrypoint.dart
@@ -154,6 +154,36 @@
return new LockFile.load(lockFilePath, cache.sources);
}
+ /// Determines whether or not the lockfile is out of date with respect to the
+ /// pubspec.
+ ///
+ /// This will be `false` if there is no lockfile at all, or if the pubspec
+ /// contains dependencies that are not in the lockfile or that don't match
+ /// what's in there.
+ bool isLockFileUpToDate() {
+ var lockFile = loadLockFile();
+
+ checkDependency(package) {
+ var locked = lockFile.packages[package.name];
+ if (locked == null) return false;
+
+ if (package.source != locked.source) return false;
+ if (!package.constraint.allows(locked.version)) return false;
+
+ var source = cache.sources[package.source];
+ if (!source.descriptionsEqual(package.description, locked.description)) {
+ return false;
+ }
+
+ return true;
+ }
+
+ if (!root.dependencies.every(checkDependency)) return false;
+ if (!root.devDependencies.every(checkDependency)) return false;
+
+ return true;
+ }
+
/// Saves a list of concrete package versions to the `pubspec.lock` file.
void _saveLockFile(List<PackageId> packageIds) {
var lockFile = new LockFile.empty();
diff --git a/sdk/lib/_internal/pub/lib/src/package.dart b/sdk/lib/_internal/pub/lib/src/package.dart
index 6f1be0b..315f189 100644
--- a/sdk/lib/_internal/pub/lib/src/package.dart
+++ b/sdk/lib/_internal/pub/lib/src/package.dart
@@ -34,10 +34,12 @@
/// The parsed pubspec associated with this package.
final Pubspec pubspec;
- /// The ids of the packages that this package depends on. This is what is
- /// specified in the pubspec when this package depends on another.
+ /// The immediate dependencies this package specifies in its pubspec.
List<PackageDep> get dependencies => pubspec.dependencies;
+ /// The immediate dev dependencies this package specifies in its pubspec.
+ List<PackageDep> get devDependencies => pubspec.devDependencies;
+
/// Returns the path to the README file at the root of the entrypoint, or null
/// if no README file is found. If multiple READMEs are found, this uses the
/// same conventions as pub.dartlang.org for choosing the primary one: the
diff --git a/sdk/lib/_internal/pub/lib/src/pub_package_provider.dart b/sdk/lib/_internal/pub/lib/src/pub_package_provider.dart
new file mode 100644
index 0000000..6243127
--- /dev/null
+++ b/sdk/lib/_internal/pub/lib/src/pub_package_provider.dart
@@ -0,0 +1,97 @@
+// Copyright (c) 2013, 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 pub.pub_package_provider;
+
+import 'dart:async';
+import 'dart:io';
+
+import 'package:barback/barback.dart';
+import 'package:path/path.dart' as path;
+
+import 'entrypoint.dart';
+import 'io.dart';
+
+/// An implementation of barback's [PackageProvider] interface so that barback
+/// can assets within pub packages.
+class PubPackageProvider implements PackageProvider {
+ /// The [Entrypoint] package being served.
+ final Entrypoint _entrypoint;
+
+ /// Maps the names of all of the packages in [_entrypoint]'s transitive
+ /// dependency graph to the local path of the directory for that package.
+ final Map<String, String> _packageDirs;
+
+ /// Creates a new provider for [entrypoint].
+ static Future<PubPackageProvider> create(Entrypoint entrypoint) {
+ var packageDirs = <String, String>{};
+
+ packageDirs[entrypoint.root.name] = entrypoint.root.dir;
+
+ // Cache package directories up front so we can have synchronous access
+ // to them.
+ // TODO(rnystrom): Handle missing or out of date lockfile.
+ var futures = [];
+ entrypoint.loadLockFile().packages.forEach((name, package) {
+ var source = entrypoint.cache.sources[package.source];
+ futures.add(source.getDirectory(package).then((packageDir) {
+ packageDirs[name] = packageDir;
+ }));
+ });
+
+ return Future.wait(futures).then((_) {
+ return new PubPackageProvider._(entrypoint, packageDirs);
+ });
+ }
+
+ PubPackageProvider._(this._entrypoint, this._packageDirs);
+
+ Iterable<String> get packages => _packageDirs.keys;
+
+ /// Lists all of the visible files in [package].
+ ///
+ /// This is the recursive contents of the "asset" and "lib" directories (if
+ /// present). If [package] is the entrypoint package, it also includes the
+ /// contents of "web".
+ List<AssetId> listAssets(String package) {
+ var files = <AssetId>[];
+
+ addFiles(String dirPath) {
+ var packageDir = _packageDirs[package];
+ var dir = path.join(packageDir, dirPath);
+ if (!dirExists(dir)) return;
+ for (var entry in listDir(dir, recursive: true)) {
+ // Ignore "packages" symlinks if there.
+ if (path.split(entry).contains("packages")) continue;
+
+ // Skip directories.
+ if (!fileExists(entry)) continue;
+
+ // AssetId paths use "/" on all platforms.
+ var relative = path.relative(entry, from: packageDir);
+ relative = path.toUri(relative).path;
+ files.add(new AssetId(package, relative));
+ }
+ }
+
+ // Expose the "asset" and "lib" directories.
+ addFiles("asset");
+ addFiles("lib");
+
+ // The entrypoint's "web" directory is also visible.
+ if (package == _entrypoint.root.name) {
+ addFiles("web");
+ }
+
+ return files;
+ }
+
+ // TODO(rnystrom): Actually support transformers.
+ Iterable<Iterable<Transformer>> getTransformers(String package) => [];
+
+ Future<Asset> getAsset(AssetId id) {
+ var file = path.join(_packageDirs[id.package], id.path);
+ return new Future.value(new Asset.fromPath(id, file));
+ }
+}
diff --git a/sdk/lib/_internal/pub/lib/src/source.dart b/sdk/lib/_internal/pub/lib/src/source.dart
index 66428f5..99f12ab 100644
--- a/sdk/lib/_internal/pub/lib/src/source.dart
+++ b/sdk/lib/_internal/pub/lib/src/source.dart
@@ -184,6 +184,14 @@
return false;
}
+ /// Returns the directory where this package has been installed. If this is
+ /// a cached source, it will be in the system cache. Otherwise, it will
+ /// depend on the source.
+ Future<String> getDirectory(PackageId id) {
+ if (shouldCache) return systemCacheDirectory(id);
+ throw new UnimplementedError("Source $name must implement this.");
+ }
+
/// Returns the directory in the system cache that the package identified by
/// [id] should be installed to. This should return a path to a subdirectory
/// of [systemCacheRoot].
diff --git a/sdk/lib/_internal/pub/lib/src/source/path.dart b/sdk/lib/_internal/pub/lib/src/source/path.dart
index 809481e..6a9363a 100644
--- a/sdk/lib/_internal/pub/lib/src/source/path.dart
+++ b/sdk/lib/_internal/pub/lib/src/source/path.dart
@@ -52,6 +52,13 @@
});
}
+ Future<String> getDirectory(PackageId id) {
+ return newFuture(() {
+ _validatePath(id.name, id.description);
+ return id.description["path"];
+ });
+ }
+
/// Parses a path dependency. This takes in a path string and returns a map.
/// The "path" key will be the original path but resolved relative to the
/// containing path. The "relative" key will be `true` if the original path
diff --git a/sdk/lib/_internal/pub/lib/src/utils.dart b/sdk/lib/_internal/pub/lib/src/utils.dart
index 16e7bef..6a048cf 100644
--- a/sdk/lib/_internal/pub/lib/src/utils.dart
+++ b/sdk/lib/_internal/pub/lib/src/utils.dart
@@ -72,6 +72,14 @@
Future<List> get future => _completer.future;
}
+/// Returns [posix] on POSIX machines and [windows] on Windows.
+///
+/// If [windows] is omitted, returns `""` on Windows.
+String getPlatformString(String posix, [String windows]) {
+ if (windows == null) windows = "";
+ return Platform.operatingSystem == "windows" ? windows : posix;
+}
+
/// Like [new Future], but avoids around issue 11911 by using [new Future.value]
/// under the covers.
Future newFuture(callback()) => new Future.value().then((_) => callback());
diff --git a/sdk/lib/_internal/pub/test/pub_test.dart b/sdk/lib/_internal/pub/test/pub_test.dart
index 949f437..a521491 100644
--- a/sdk/lib/_internal/pub/test/pub_test.dart
+++ b/sdk/lib/_internal/pub/test/pub_test.dart
@@ -35,6 +35,7 @@
help Display help information for Pub.
install Install the current package's dependencies.
publish Publish the current package to pub.dartlang.org.
+ serve Run a local web development server.
update Update the current package's dependencies to the latest versions.
uploader Manage uploaders for a package on pub.dartlang.org.
version Print pub version.
diff --git a/sdk/lib/_internal/pub/test/serve/does_not_install_first_if_a_dependency_is_removed_test.dart b/sdk/lib/_internal/pub/test/serve/does_not_install_first_if_a_dependency_is_removed_test.dart
new file mode 100644
index 0000000..8166680
--- /dev/null
+++ b/sdk/lib/_internal/pub/test/serve/does_not_install_first_if_a_dependency_is_removed_test.dart
@@ -0,0 +1,39 @@
+// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS d.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 pub_tests;
+
+import 'dart:io';
+import 'dart:json' as json;
+
+import '../descriptor.dart' as d;
+import '../test_pub.dart';
+import 'utils.dart';
+
+main() {
+ initConfig();
+ integration("does not install if a dependency is removed", () {
+ d.dir("foo", [
+ d.libPubspec("foo", "0.0.1"),
+ d.libDir("foo")
+ ]).create();
+
+ // Install to get "foo" into the lock file.
+ d.dir(appPath, [
+ d.appPubspec({
+ "foo": {"path": "../foo"}
+ })
+ ]).create();
+ pubInstall();
+
+ // Remove it from the pubspec.
+ d.dir(appPath, [
+ d.appPubspec()
+ ]).create();
+
+ startPubServe(shouldInstallFirst: false);
+ requestShouldSucceed("packages/foo/foo.dart", 'main() => "foo";');
+ endPubServe();
+ });
+}
diff --git a/sdk/lib/_internal/pub/test/serve/does_not_install_first_if_git_url_did_not_change_test.dart b/sdk/lib/_internal/pub/test/serve/does_not_install_first_if_git_url_did_not_change_test.dart
new file mode 100644
index 0000000..ee92c92
--- /dev/null
+++ b/sdk/lib/_internal/pub/test/serve/does_not_install_first_if_git_url_did_not_change_test.dart
@@ -0,0 +1,32 @@
+// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS d.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 pub_tests;
+
+import 'dart:io';
+import 'dart:json' as json;
+
+import '../descriptor.dart' as d;
+import '../test_pub.dart';
+import 'utils.dart';
+
+main() {
+ initConfig();
+ integration("does not install first if a git dependency's url is "
+ "unchanged", () {
+ d.git('foo.git', [
+ d.libPubspec('foo', '1.0.0'),
+ d.libDir("foo")
+ ]).create();
+
+ d.appDir({
+ "foo": {"git": "../foo.git"}
+ }).create();
+
+ pubInstall();
+ startPubServe(shouldInstallFirst: false);
+ requestShouldSucceed("packages/foo/foo.dart", 'main() => "foo";');
+ endPubServe();
+ });
+}
diff --git a/sdk/lib/_internal/pub/test/serve/does_not_install_first_if_locked_version_matches_test.dart b/sdk/lib/_internal/pub/test/serve/does_not_install_first_if_locked_version_matches_test.dart
new file mode 100644
index 0000000..fd2c2ff
--- /dev/null
+++ b/sdk/lib/_internal/pub/test/serve/does_not_install_first_if_locked_version_matches_test.dart
@@ -0,0 +1,48 @@
+// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS d.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 pub_tests;
+
+import 'dart:io';
+import 'dart:json' as json;
+
+import '../descriptor.dart' as d;
+import '../test_pub.dart';
+import 'utils.dart';
+
+main() {
+ initConfig();
+ integration("does not install if the locked version of a dependency is "
+ "allowed by the pubspec's constraint", () {
+ d.dir("foo", [
+ d.libPubspec("foo", "0.0.1"),
+ d.libDir("foo")
+ ]).create();
+
+ // Install to get "foo" into the lock file.
+ d.dir(appPath, [
+ d.appPubspec({
+ "foo": {
+ "path": "../foo",
+ "version": ">=0.0.1"
+ },
+ })
+ ]).create();
+ pubInstall();
+
+ // Change the version.
+ d.dir(appPath, [
+ d.appPubspec({
+ "foo": {
+ "path": "../foo",
+ "version": "<2.0.0"
+ },
+ })
+ ]).create();
+
+ startPubServe(shouldInstallFirst: false);
+ requestShouldSucceed("packages/foo/foo.dart", 'main() => "foo";');
+ endPubServe();
+ });
+}
diff --git a/sdk/lib/_internal/pub/test/serve/installs_first_if_dependency_added_test.dart b/sdk/lib/_internal/pub/test/serve/installs_first_if_dependency_added_test.dart
new file mode 100644
index 0000000..42bcdfd
--- /dev/null
+++ b/sdk/lib/_internal/pub/test/serve/installs_first_if_dependency_added_test.dart
@@ -0,0 +1,39 @@
+// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS d.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 pub_tests;
+
+import 'dart:io';
+import 'dart:json' as json;
+
+import '../descriptor.dart' as d;
+import '../test_pub.dart';
+import 'utils.dart';
+
+main() {
+ initConfig();
+ integration("installs first if a dependency is not in the lock file", () {
+ d.dir("foo", [
+ d.libPubspec("foo", "0.0.1"),
+ d.libDir("foo")
+ ]).create();
+
+ // Create a lock file without "foo".
+ d.dir(appPath, [
+ d.appPubspec()
+ ]).create();
+ pubInstall();
+
+ // Add it to the pubspec.
+ d.dir(appPath, [
+ d.appPubspec({
+ "foo": {"path": "../foo"}
+ })
+ ]).create();
+
+ startPubServe(shouldInstallFirst: true);
+ requestShouldSucceed("packages/foo/foo.dart", 'main() => "foo";');
+ endPubServe();
+ });
+}
diff --git a/sdk/lib/_internal/pub/test/serve/installs_first_if_dependency_version_changed_test.dart b/sdk/lib/_internal/pub/test/serve/installs_first_if_dependency_version_changed_test.dart
new file mode 100644
index 0000000..cb64373
--- /dev/null
+++ b/sdk/lib/_internal/pub/test/serve/installs_first_if_dependency_version_changed_test.dart
@@ -0,0 +1,49 @@
+// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS d.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 pub_tests;
+
+import 'dart:io';
+import 'dart:json' as json;
+
+import '../descriptor.dart' as d;
+import '../test_pub.dart';
+import 'utils.dart';
+
+main() {
+ initConfig();
+ integration("installs first if a dependency's version doesn't match the one "
+ "in the lock file", () {
+ d.dir("foo", [
+ d.libPubspec("foo", "0.0.1"),
+ d.libDir("foo")
+ ]).create();
+
+ d.appDir({
+ "foo": {
+ "path": "../foo",
+ "version": "0.0.1"
+ }
+ }).create();
+
+ pubInstall();
+
+ // Change the version in the pubspec and package.
+ d.appDir({
+ "foo": {
+ "path": "../foo",
+ "version": "0.0.2"
+ }
+ }).create();
+
+ d.dir("foo", [
+ d.libPubspec("foo", "0.0.2"),
+ d.libDir("foo")
+ ]).create();
+
+ startPubServe(shouldInstallFirst: true);
+ requestShouldSucceed("packages/foo/foo.dart", 'main() => "foo";');
+ endPubServe();
+ });
+}
diff --git a/sdk/lib/_internal/pub/test/serve/installs_first_if_dev_dependency_changed_test.dart b/sdk/lib/_internal/pub/test/serve/installs_first_if_dev_dependency_changed_test.dart
new file mode 100644
index 0000000..5854fb6
--- /dev/null
+++ b/sdk/lib/_internal/pub/test/serve/installs_first_if_dev_dependency_changed_test.dart
@@ -0,0 +1,39 @@
+// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS d.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 pub_tests;
+
+import 'dart:io';
+import 'dart:json' as json;
+
+import '../descriptor.dart' as d;
+import '../test_pub.dart';
+import 'utils.dart';
+
+main() {
+ initConfig();
+ integration("installs first if a dev dependency has changed", () {
+ d.dir("foo", [
+ d.libPubspec("foo", "0.0.1"),
+ d.libDir("foo")
+ ]).create();
+
+ // Create a pubspec with "foo" and a lock file without it.
+ d.dir(appPath, [
+ d.pubspec({
+ "name": "myapp",
+ "dev_dependencies": {
+ "foo": {"path": "../foo"}
+ }
+ }),
+ d.file("pubspec.lock", json.stringify({
+ 'packages': {}
+ }))
+ ]).create();
+
+ startPubServe(shouldInstallFirst: true);
+ requestShouldSucceed("packages/foo/foo.dart", 'main() => "foo";');
+ endPubServe();
+ });
+}
diff --git a/sdk/lib/_internal/pub/test/serve/installs_first_if_git_ref_changed_test.dart b/sdk/lib/_internal/pub/test/serve/installs_first_if_git_ref_changed_test.dart
new file mode 100644
index 0000000..a1906fd
--- /dev/null
+++ b/sdk/lib/_internal/pub/test/serve/installs_first_if_git_ref_changed_test.dart
@@ -0,0 +1,48 @@
+// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS d.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 pub_tests;
+
+import 'dart:io';
+import 'dart:json' as json;
+
+import '../descriptor.dart' as d;
+import '../test_pub.dart';
+import 'utils.dart';
+
+main() {
+ initConfig();
+ integration("installs first if a git dependency's ref doesn't match the one "
+ "in the lock file", () {
+ var repo = d.git('foo.git', [
+ d.libDir('foo', 'before'),
+ d.libPubspec('foo', '1.0.0')
+ ]);
+ repo.create();
+ var commit1 = repo.revParse('HEAD');
+
+ d.git('foo.git', [
+ d.libDir('foo', 'after'),
+ d.libPubspec('foo', '1.0.0')
+ ]).commit();
+
+ var commit2 = repo.revParse('HEAD');
+
+ // Lock it to the ref of the first commit.
+ d.appDir({
+ "foo": {"git": {"url": "../foo.git", "ref": commit1}}
+ }).create();
+
+ pubInstall();
+
+ // Change the commit in the pubspec.
+ d.appDir({
+ "foo": {"git": {"url": "../foo.git", "ref": commit2}}
+ }).create();
+
+ startPubServe(shouldInstallFirst: true);
+ requestShouldSucceed("packages/foo/foo.dart", 'main() => "after";');
+ endPubServe();
+ });
+}
diff --git a/sdk/lib/_internal/pub/test/serve/installs_first_if_git_url_changed_test.dart b/sdk/lib/_internal/pub/test/serve/installs_first_if_git_url_changed_test.dart
new file mode 100644
index 0000000..844e293
--- /dev/null
+++ b/sdk/lib/_internal/pub/test/serve/installs_first_if_git_url_changed_test.dart
@@ -0,0 +1,43 @@
+// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS d.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 pub_tests;
+
+import 'dart:io';
+import 'dart:json' as json;
+
+import '../descriptor.dart' as d;
+import '../test_pub.dart';
+import 'utils.dart';
+
+main() {
+ initConfig();
+ integration("installs first if a git dependency's url doesn't match the one "
+ "in the lock file", () {
+ d.git("foo-before.git", [
+ d.libPubspec("foo", "1.0.0"),
+ d.libDir("foo", "before")
+ ]).create();
+
+ d.git("foo-after.git", [
+ d.libPubspec("foo", "1.0.0"),
+ d.libDir("foo", "after")
+ ]).create();
+
+ d.appDir({
+ "foo": {"git": "../foo-before.git"}
+ }).create();
+
+ pubInstall();
+
+ // Change the path in the pubspec.
+ d.appDir({
+ "foo": {"git": "../foo-after.git"}
+ }).create();
+
+ startPubServe(shouldInstallFirst: true);
+ requestShouldSucceed("packages/foo/foo.dart", 'main() => "after";');
+ endPubServe();
+ });
+}
diff --git a/sdk/lib/_internal/pub/test/serve/installs_first_if_no_lockfile_test.dart b/sdk/lib/_internal/pub/test/serve/installs_first_if_no_lockfile_test.dart
new file mode 100644
index 0000000..9988113
--- /dev/null
+++ b/sdk/lib/_internal/pub/test/serve/installs_first_if_no_lockfile_test.dart
@@ -0,0 +1,29 @@
+// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS d.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 pub_tests;
+
+import 'dart:io';
+
+import '../descriptor.dart' as d;
+import '../test_pub.dart';
+import 'utils.dart';
+
+main() {
+ initConfig();
+ integration("installs first if there is no lockfile", () {
+ d.dir("foo", [
+ d.libPubspec("foo", "0.0.1"),
+ d.libDir("foo")
+ ]).create();
+
+ d.appDir({
+ "foo": {"path": "../foo"}
+ }).create();
+
+ startPubServe(shouldInstallFirst: true);
+ requestShouldSucceed("packages/foo/foo.dart", 'main() => "foo";');
+ endPubServe();
+ });
+}
diff --git a/sdk/lib/_internal/pub/test/serve/installs_first_if_path_dependency_changed_test.dart b/sdk/lib/_internal/pub/test/serve/installs_first_if_path_dependency_changed_test.dart
new file mode 100644
index 0000000..0380a9a
--- /dev/null
+++ b/sdk/lib/_internal/pub/test/serve/installs_first_if_path_dependency_changed_test.dart
@@ -0,0 +1,43 @@
+// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS d.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 pub_tests;
+
+import 'dart:io';
+import 'dart:json' as json;
+
+import '../descriptor.dart' as d;
+import '../test_pub.dart';
+import 'utils.dart';
+
+main() {
+ initConfig();
+ integration("installs first if a path dependency's path doesn't match the "
+ "one in the lock file", () {
+ d.dir("foo-before", [
+ d.libPubspec("foo", "0.0.1"),
+ d.libDir("foo", "before")
+ ]).create();
+
+ d.dir("foo-after", [
+ d.libPubspec("foo", "0.0.1"),
+ d.libDir("foo", "after")
+ ]).create();
+
+ d.appDir({
+ "foo": {"path": "../foo-before"}
+ }).create();
+
+ pubInstall();
+
+ // Change the path in the pubspec.
+ d.appDir({
+ "foo": {"path": "../foo-after"}
+ }).create();
+
+ startPubServe(shouldInstallFirst: true);
+ requestShouldSucceed("packages/foo/foo.dart", 'main() => "after";');
+ endPubServe();
+ });
+}
diff --git a/sdk/lib/_internal/pub/test/serve/installs_first_if_source_changed_test.dart b/sdk/lib/_internal/pub/test/serve/installs_first_if_source_changed_test.dart
new file mode 100644
index 0000000..85d0eee
--- /dev/null
+++ b/sdk/lib/_internal/pub/test/serve/installs_first_if_source_changed_test.dart
@@ -0,0 +1,44 @@
+// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS d.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 pub_tests;
+
+import 'dart:io';
+import 'dart:json' as json;
+
+import '../descriptor.dart' as d;
+import '../test_pub.dart';
+import 'utils.dart';
+
+main() {
+ initConfig();
+ integration("installs first if a dependency's source doesn't match the one "
+ "in the lock file", () {
+ d.dir("foo", [
+ d.libPubspec("foo", "0.0.1"),
+ d.libDir("foo")
+ ]).create();
+
+ d.dir(appPath, [
+ // A pubspec with a path source.
+ d.appPubspec({
+ "foo": {"path": "../foo"}
+ }),
+ // A lock file with the hosted source.
+ d.file("pubspec.lock", json.stringify({
+ 'packages': {
+ 'foo': {
+ 'version': '0.0.0',
+ 'source': 'hosted',
+ 'description': 'foo'
+ }
+ }
+ }))
+ ]).create();
+
+ startPubServe(shouldInstallFirst: true);
+ requestShouldSucceed("packages/foo/foo.dart", 'main() => "foo";');
+ endPubServe();
+ });
+}
diff --git a/sdk/lib/_internal/pub/test/serve/invalid_urls_test.dart b/sdk/lib/_internal/pub/test/serve/invalid_urls_test.dart
new file mode 100644
index 0000000..bb830733
--- /dev/null
+++ b/sdk/lib/_internal/pub/test/serve/invalid_urls_test.dart
@@ -0,0 +1,61 @@
+// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS d.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 pub_tests;
+
+import 'dart:io';
+
+import '../descriptor.dart' as d;
+import '../test_pub.dart';
+import 'utils.dart';
+
+main() {
+ initConfig();
+ integration("responds with a 404 on incomplete special URLs", () {
+ d.dir("foo", [
+ d.libPubspec("foo", "0.0.1")
+ ]).create();
+
+ d.dir(appPath, [
+ d.appPubspec({
+ "foo": {"path": "../foo"}
+ }),
+ // Make files that map to the special directory names to ensure they
+ // are *not* found.
+ d.dir("asset", [
+ d.file("packages"),
+ d.file("assets")
+ ]),
+ d.dir("lib", [
+ d.file("packages"),
+ d.file("assets")
+ ]),
+ d.dir("web", [
+ d.file("packages"),
+ d.file("assets")
+ ])
+ ]).create();
+
+ pubInstall();
+ startPubServe();
+ requestShould404("packages");
+ requestShould404("assets");
+ requestShould404("packages/");
+ requestShould404("assets/");
+ requestShould404("packages/myapp");
+ requestShould404("assets/myapp");
+ requestShould404("packages/myapp/");
+ requestShould404("assets/myapp/");
+ requestShould404("packages/foo");
+ requestShould404("assets/foo");
+ requestShould404("packages/foo/");
+ requestShould404("assets/foo/");
+ requestShould404("packages/unknown");
+ requestShould404("assets/unknown");
+ requestShould404("packages/unknown/");
+ requestShould404("assets/unknown/");
+ endPubServe();
+ });
+
+}
diff --git a/sdk/lib/_internal/pub/test/serve/missing_dependency_file_test.dart b/sdk/lib/_internal/pub/test/serve/missing_dependency_file_test.dart
new file mode 100644
index 0000000..d1c47f2
--- /dev/null
+++ b/sdk/lib/_internal/pub/test/serve/missing_dependency_file_test.dart
@@ -0,0 +1,34 @@
+// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS d.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 pub_tests;
+
+import 'dart:io';
+
+import '../descriptor.dart' as d;
+import '../test_pub.dart';
+import 'utils.dart';
+
+main() {
+ initConfig();
+ integration("responds with a 404 for a missing files in dependencies", () {
+ d.dir("foo", [
+ d.libPubspec("foo", "0.0.1")
+ ]).create();
+
+ d.dir(appPath, [
+ d.appPubspec({
+ "foo": {"path": "../foo"}
+ })
+ ]).create();
+
+ pubInstall();
+ startPubServe();
+ requestShould404("packages/foo/nope.dart");
+ requestShould404("assets/foo/nope.png");
+ requestShould404("dir/packages/foo/nope.dart");
+ requestShould404("dir/assets/foo/nope.png");
+ endPubServe();
+ });
+}
diff --git a/sdk/lib/_internal/pub/test/serve/missing_file_test.dart b/sdk/lib/_internal/pub/test/serve/missing_file_test.dart
new file mode 100644
index 0000000..cfd7d07
--- /dev/null
+++ b/sdk/lib/_internal/pub/test/serve/missing_file_test.dart
@@ -0,0 +1,28 @@
+// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS d.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 pub_tests;
+
+import 'dart:io';
+
+import '../descriptor.dart' as d;
+import '../test_pub.dart';
+import 'utils.dart';
+
+main() {
+ initConfig();
+ integration("responds with a 404 for missing files", () {
+ d.dir(appPath, [
+ d.appPubspec()
+ ]).create();
+
+ startPubServe();
+ requestShould404("index.html");
+ requestShould404("packages/myapp/nope.dart");
+ requestShould404("assets/myapp/nope.png");
+ requestShould404("dir/packages/myapp/nope.dart");
+ requestShould404("dir/assets/myapp/nope.png");
+ endPubServe();
+ });
+}
diff --git a/sdk/lib/_internal/pub/test/serve/serve_from_app_asset_test.dart b/sdk/lib/_internal/pub/test/serve/serve_from_app_asset_test.dart
new file mode 100644
index 0000000..1f072fc
--- /dev/null
+++ b/sdk/lib/_internal/pub/test/serve/serve_from_app_asset_test.dart
@@ -0,0 +1,35 @@
+// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS d.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 pub_tests;
+
+import 'dart:io';
+
+import '../descriptor.dart' as d;
+import '../test_pub.dart';
+import 'utils.dart';
+
+main() {
+ initConfig();
+ integration("'assets' URLs look in the app's 'asset' directory", () {
+ d.dir(appPath, [
+ d.appPubspec(),
+ d.dir("asset", [
+ d.file("foo.txt", "foo"),
+ d.dir("sub", [
+ d.file("bar.txt", "bar"),
+ ])
+ ])
+ ]).create();
+
+ startPubServe();
+ requestShouldSucceed("assets/myapp/foo.txt", "foo");
+ requestShouldSucceed("assets/myapp/sub/bar.txt", "bar");
+
+ // "assets" can be in a subpath of the URL:
+ requestShouldSucceed("foo/assets/myapp/foo.txt", "foo");
+ requestShouldSucceed("a/b/assets/myapp/sub/bar.txt", "bar");
+ endPubServe();
+ });
+}
diff --git a/sdk/lib/_internal/pub/test/serve/serve_from_app_lib_test.dart b/sdk/lib/_internal/pub/test/serve/serve_from_app_lib_test.dart
new file mode 100644
index 0000000..0ddea5f
--- /dev/null
+++ b/sdk/lib/_internal/pub/test/serve/serve_from_app_lib_test.dart
@@ -0,0 +1,35 @@
+// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS d.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 pub_tests;
+
+import 'dart:io';
+
+import '../descriptor.dart' as d;
+import '../test_pub.dart';
+import 'utils.dart';
+
+main() {
+ initConfig();
+ integration("'packages' URLs look in the app's lib directory", () {
+ d.dir(appPath, [
+ d.appPubspec(),
+ d.dir("lib", [
+ d.file("lib.dart", "foo() => 'foo';"),
+ d.dir("sub", [
+ d.file("lib.dart", "bar() => 'bar';"),
+ ])
+ ])
+ ]).create();
+
+ startPubServe();
+ requestShouldSucceed("packages/myapp/lib.dart", "foo() => 'foo';");
+ requestShouldSucceed("packages/myapp/sub/lib.dart", "bar() => 'bar';");
+
+ // "packages" can be in a subpath of the URL:
+ requestShouldSucceed("foo/packages/myapp/lib.dart", "foo() => 'foo';");
+ requestShouldSucceed("a/b/packages/myapp/sub/lib.dart", "bar() => 'bar';");
+ endPubServe();
+ });
+}
diff --git a/sdk/lib/_internal/pub/test/serve/serve_from_app_web_test.dart b/sdk/lib/_internal/pub/test/serve/serve_from_app_web_test.dart
new file mode 100644
index 0000000..9c0a7f5
--- /dev/null
+++ b/sdk/lib/_internal/pub/test/serve/serve_from_app_web_test.dart
@@ -0,0 +1,35 @@
+// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS d.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 pub_tests;
+
+import 'dart:io';
+
+import '../descriptor.dart' as d;
+import '../test_pub.dart';
+import 'utils.dart';
+
+main() {
+ initConfig();
+ integration("finds files in the app's web directory", () {
+ d.dir(appPath, [
+ d.appPubspec(),
+ d.dir("web", [
+ d.file("index.html", "<body>"),
+ d.file("file.dart", "void main() => print('hello');"),
+ d.dir("sub", [
+ d.file("file.html", "<body>in subdir</body>"),
+ d.file("lib.dart", "void foo() => 'foo';"),
+ ])
+ ])
+ ]).create();
+
+ startPubServe();
+ requestShouldSucceed("index.html", "<body>");
+ requestShouldSucceed("file.dart", "void main() => print('hello');");
+ requestShouldSucceed("sub/file.html", "<body>in subdir</body>");
+ requestShouldSucceed("sub/lib.dart", "void foo() => 'foo';");
+ endPubServe();
+ });
+}
diff --git a/sdk/lib/_internal/pub/test/serve/serve_from_dependency_asset_test.dart b/sdk/lib/_internal/pub/test/serve/serve_from_dependency_asset_test.dart
new file mode 100644
index 0000000..f30d72c
--- /dev/null
+++ b/sdk/lib/_internal/pub/test/serve/serve_from_dependency_asset_test.dart
@@ -0,0 +1,42 @@
+// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS d.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 pub_tests;
+
+import 'dart:io';
+
+import '../descriptor.dart' as d;
+import '../test_pub.dart';
+import 'utils.dart';
+
+main() {
+ initConfig();
+ integration("'assets' URLs look in the dependency's asset directory", () {
+ d.dir("foo", [
+ d.libPubspec("foo", "0.0.1"),
+ d.dir("asset", [
+ d.file("foo.txt", "foo"),
+ d.dir("sub", [
+ d.file("bar.txt", "bar"),
+ ])
+ ])
+ ]).create();
+
+ d.dir(appPath, [
+ d.appPubspec({
+ "foo": {"path": "../foo"}
+ })
+ ]).create();
+
+ pubInstall();
+ startPubServe();
+ requestShouldSucceed("assets/foo/foo.txt", "foo");
+ requestShouldSucceed("assets/foo/sub/bar.txt", "bar");
+
+ // "assets" can be in a subpath of the URL:
+ requestShouldSucceed("foo/assets/foo/foo.txt", "foo");
+ requestShouldSucceed("a/b/assets/foo/sub/bar.txt", "bar");
+ endPubServe();
+ });
+}
diff --git a/sdk/lib/_internal/pub/test/serve/serve_from_dependency_lib_test.dart b/sdk/lib/_internal/pub/test/serve/serve_from_dependency_lib_test.dart
new file mode 100644
index 0000000..a6a9ab2
--- /dev/null
+++ b/sdk/lib/_internal/pub/test/serve/serve_from_dependency_lib_test.dart
@@ -0,0 +1,42 @@
+// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS d.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 pub_tests;
+
+import 'dart:io';
+
+import '../descriptor.dart' as d;
+import '../test_pub.dart';
+import 'utils.dart';
+
+main() {
+ initConfig();
+ integration("'packages' URLs look in the dependency's lib directory", () {
+ d.dir("foo", [
+ d.libPubspec("foo", "0.0.1"),
+ d.dir("lib", [
+ d.file("lib.dart", "foo() => 'foo';"),
+ d.dir("sub", [
+ d.file("lib.dart", "bar() => 'bar';"),
+ ])
+ ])
+ ]).create();
+
+ d.dir(appPath, [
+ d.appPubspec({
+ "foo": {"path": "../foo"}
+ })
+ ]).create();
+
+ pubInstall();
+ startPubServe();
+ requestShouldSucceed("packages/foo/lib.dart", "foo() => 'foo';");
+ requestShouldSucceed("packages/foo/sub/lib.dart", "bar() => 'bar';");
+
+ // "packages" can be in a subpath of the URL:
+ requestShouldSucceed("foo/packages/foo/lib.dart", "foo() => 'foo';");
+ requestShouldSucceed("a/b/packages/foo/sub/lib.dart", "bar() => 'bar';");
+ endPubServe();
+ });
+}
diff --git a/sdk/lib/_internal/pub/test/serve/unknown_dependency_test.dart b/sdk/lib/_internal/pub/test/serve/unknown_dependency_test.dart
new file mode 100644
index 0000000..434a84c
--- /dev/null
+++ b/sdk/lib/_internal/pub/test/serve/unknown_dependency_test.dart
@@ -0,0 +1,27 @@
+// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS d.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 pub_tests;
+
+import 'dart:io';
+
+import '../descriptor.dart' as d;
+import '../test_pub.dart';
+import 'utils.dart';
+
+main() {
+ initConfig();
+ integration("responds with a 404 unknown dependencies", () {
+ d.dir(appPath, [
+ d.appPubspec()
+ ]).create();
+
+ startPubServe();
+ requestShould404("packages/foo/nope.dart");
+ requestShould404("assets/foo/nope.png");
+ requestShould404("dir/packages/foo/nope.dart");
+ requestShould404("dir/assets/foo/nope.png");
+ endPubServe();
+ });
+}
diff --git a/sdk/lib/_internal/pub/test/serve/utils.dart b/sdk/lib/_internal/pub/test/serve/utils.dart
new file mode 100644
index 0000000..e03edd0
--- /dev/null
+++ b/sdk/lib/_internal/pub/test/serve/utils.dart
@@ -0,0 +1,72 @@
+// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS d.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 pub_tests;
+
+import 'dart:async';
+import 'dart:io';
+
+import 'package:http/http.dart' as http;
+import 'package:scheduled_test/scheduled_process.dart';
+import 'package:scheduled_test/scheduled_test.dart';
+
+import '../descriptor.dart' as d;
+import '../test_pub.dart';
+
+/// The pub process running "pub serve".
+ScheduledProcess _pubServer;
+
+/// The ephemeral port assigned to the running server.
+int _port;
+
+/// Schedules starting the "pub serve" process.
+///
+/// If [shouldInstallFirst] is `true`, validates that pub install is run first.
+void startPubServe({bool shouldInstallFirst: false}) {
+ // Use port 0 to get an ephemeral port.
+ _pubServer = startPub(args: ["serve", "--port=0"]);
+
+ if (shouldInstallFirst) {
+ expect(_pubServer.nextLine(),
+ completion(startsWith("Dependencies have changed")));
+ expect(_pubServer.nextLine(),
+ completion(startsWith("Resolving dependencies...")));
+ expect(_pubServer.nextLine(),
+ completion(equals("Dependencies installed!")));
+ }
+
+ expect(_pubServer.nextLine().then(_parsePort), completes);
+}
+
+/// Parses the port number from the "Serving blah on localhost:1234" line
+/// printed by pub serve.
+void _parsePort(String line) {
+ var match = new RegExp(r"localhost:(\d+)").firstMatch(line);
+ assert(match != null);
+ _port = int.parse(match[1]);
+}
+
+void endPubServe() {
+ _pubServer.kill();
+}
+
+/// Schedules an HTTP request to the running pub server with [urlPath] and
+/// verifies that it responds with [expected].
+void requestShouldSucceed(String urlPath, String expected) {
+ schedule(() {
+ return http.get("http://localhost:$_port/$urlPath").then((response) {
+ expect(response.body, equals(expected));
+ });
+ }, "request $urlPath");
+}
+
+/// Schedules an HTTP request to the running pub server with [urlPath] and
+/// verifies that it responds with a 404.
+void requestShould404(String urlPath) {
+ schedule(() {
+ return http.get("http://localhost:$_port/$urlPath").then((response) {
+ expect(response.statusCode, equals(404));
+ });
+ }, "request $urlPath");
+}
\ No newline at end of file
diff --git a/sdk/lib/html/dart2js/html_dart2js.dart b/sdk/lib/html/dart2js/html_dart2js.dart
index 6bd9e6c..74a14e5 100644
--- a/sdk/lib/html/dart2js/html_dart2js.dart
+++ b/sdk/lib/html/dart2js/html_dart2js.dart
@@ -199,39 +199,6 @@
@DocsEditable()
-@DomName('ANGLEInstancedArrays')
-@Experimental() // untriaged
-class AngleInstancedArrays extends Interceptor native "ANGLEInstancedArrays" {
-
- @DomName('ANGLEInstancedArrays.VERTEX_ATTRIB_ARRAY_DIVISOR_ANGLE')
- @DocsEditable()
- @Experimental() // untriaged
- static const int VERTEX_ATTRIB_ARRAY_DIVISOR_ANGLE = 0x88FE;
-
- @JSName('drawArraysInstancedANGLE')
- @DomName('ANGLEInstancedArrays.drawArraysInstancedANGLE')
- @DocsEditable()
- @Experimental() // untriaged
- void drawArraysInstancedAngle(int mode, int first, int count, int primcount) native;
-
- @JSName('drawElementsInstancedANGLE')
- @DomName('ANGLEInstancedArrays.drawElementsInstancedANGLE')
- @DocsEditable()
- @Experimental() // untriaged
- void drawElementsInstancedAngle(int mode, int count, int type, int offset, int primcount) native;
-
- @JSName('vertexAttribDivisorANGLE')
- @DomName('ANGLEInstancedArrays.vertexAttribDivisorANGLE')
- @DocsEditable()
- @Experimental() // untriaged
- void vertexAttribDivisorAngle(int index, int divisor) native;
-}
-// Copyright (c) 2012, 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.
-
-
-@DocsEditable()
@DomName('WebKitAnimationEvent')
@SupportedBrowser(SupportedBrowser.CHROME)
@SupportedBrowser(SupportedBrowser.SAFARI)
@@ -2634,7 +2601,8 @@
@DomName('CSSStyleDeclaration')
-class CssStyleDeclaration extends Interceptor native "CSSStyleDeclaration,MSStyleCSSProperties,CSS2Properties" {
+ class CssStyleDeclaration extends Interceptor with
+ CssStyleDeclarationBase native "CSSStyleDeclaration,MSStyleCSSProperties,CSS2Properties" {
factory CssStyleDeclaration() => new CssStyleDeclaration.css('');
factory CssStyleDeclaration.css(String css) {
@@ -2642,7 +2610,37 @@
style.cssText = css;
return style;
}
+
+ String getPropertyValue(String propertyName) {
+ var propValue = _getPropertyValue(propertyName);
+ return propValue != null ? propValue : '';
+ }
+ @DomName('CSSStyleDeclaration.setProperty')
+ void setProperty(String propertyName, String value, [String priority]) {
+ // try/catch for IE9 which throws on unsupported values.
+ try {
+ if (priority == null) {
+ priority = '';
+ }
+ JS('void', '#.setProperty(#, #, #)', this, propertyName, value, priority);
+ // Bug #2772, IE9 requires a poke to actually apply the value.
+ if (JS('bool', '!!#.setAttribute', this)) {
+ JS('void', '#.setAttribute(#, #)', this, propertyName, value);
+ }
+ } catch (e) {}
+ }
+
+ /**
+ * Checks to see if CSS Transitions are supported.
+ */
+ static bool get supportsTransitions {
+ if (JS('bool', '"transition" in document.body.style')) {
+ return true;
+ }
+ var propertyName = '${Device.propertyPrefix}Transition';
+ return JS('bool', '# in document.body.style', propertyName);
+ }
@DomName('CSSStyleDeclaration.cssText')
@DocsEditable()
@@ -2677,37 +2675,35 @@
@DocsEditable()
String removeProperty(String propertyName) native;
+}
- String getPropertyValue(String propertyName) {
- var propValue = _getPropertyValue(propertyName);
- return propValue != null ? propValue : '';
+class _CssStyleDeclarationSet extends Object with CssStyleDeclarationBase {
+ final Iterable<Element> _elementIterable;
+ Iterable<CssStyleDeclaration> _elementCssStyleDeclarationSetIterable;
+
+ _CssStyleDeclarationSet(this._elementIterable) {
+ _elementCssStyleDeclarationSetIterable = new List.from(
+ _elementIterable).map((e) => e.style);
}
- @DomName('CSSStyleDeclaration.setProperty')
+ String getPropertyValue(String propertyName) =>
+ _elementCssStyleDeclarationSetIterable.first.getPropertyValue(
+ propertyName);
+
void setProperty(String propertyName, String value, [String priority]) {
- // try/catch for IE9 which throws on unsupported values.
- try {
- if (priority == null) {
- priority = '';
- }
- JS('void', '#.setProperty(#, #, #)', this, propertyName, value, priority);
- // Bug #2772, IE9 requires a poke to actually apply the value.
- if (JS('bool', '!!#.setAttribute', this)) {
- JS('void', '#.setAttribute(#, #)', this, propertyName, value);
- }
- } catch (e) {}
+ _elementCssStyleDeclarationSetIterable.forEach((e) =>
+ e.setProperty(propertyName, value, priority));
}
+ // Important note: CssStyleDeclarationSet does NOT implement every method
+ // available in CssStyleDeclaration. Some of the methods don't make so much
+ // sense in terms of having a resonable value to return when you're
+ // considering a list of Elements. You will need to manually add any of the
+ // items in the MEMBERS set if you want that functionality.
+}
- /**
- * Checks to see if CSS Transitions are supported.
- */
- static bool get supportsTransitions {
- if (JS('bool', '"transition" in document.body.style')) {
- return true;
- }
- var propertyName = '${Device.propertyPrefix}Transition';
- return JS('bool', '# in document.body.style', propertyName);
- }
+abstract class CssStyleDeclarationBase {
+ String getPropertyValue(String propertyName);
+ void setProperty(String propertyName, String value, [String priority]);
// TODO(jacobr): generate this list of properties using the existing script.
/** Gets the value of "align-content" */
@@ -7970,7 +7966,7 @@
/**
* An immutable list containing HTML elements. This list contains some
- * additional methods when compared to regular lists for ease of CSS
+ * additional methods when compared to regular lists for ease of CSS
* manipulation on a group of elements.
*/
abstract class ElementList<T extends Element> extends ListBase<T> {
@@ -7989,28 +7985,40 @@
/** Replace the classes with `value` for every element in this list. */
set classes(Iterable<String> value);
- /**
+ /**
+ * Access the union of all [CssStyleDeclaration]s that are associated with an
+ * [ElementList].
+ *
+ * Grouping the style objects all together provides easy editing of specific
+ * properties of a collection of elements. Setting a specific property value
+ * will set that property in all [Element]s in the [ElementList]. Getting a
+ * specific property value will return the value of the property of the first
+ * element in the [ElementList].
+ */
+ CssStyleDeclarationBase get style;
+
+ /**
* Access dimensions and position of the Elements in this list.
- *
+ *
* Setting the height or width properties will set the height or width
- * property for all elements in the list. This returns a rectangle with the
+ * property for all elements in the list. This returns a rectangle with the
* dimenions actually available for content
- * in this element, in pixels, regardless of this element's box-sizing
+ * in this element, in pixels, regardless of this element's box-sizing
* property. Getting the height or width returns the height or width of the
- * first Element in this list.
+ * first Element in this list.
*
* Unlike [getBoundingClientRect], the dimensions of this rectangle
* will return the same numerical height if the element is hidden or not.
*/
@Experimental()
CssRect get contentEdge;
-
+
/**
* Access dimensions and position of the first Element's content + padding box
* in this list.
- *
+ *
* This returns a rectangle with the dimenions actually available for content
- * in this element, in pixels, regardless of this element's box-sizing
+ * in this element, in pixels, regardless of this element's box-sizing
* property. Unlike [getBoundingClientRect], the dimensions of this rectangle
* will return the same numerical height if the element is hidden or not. This
* can be used to retrieve jQuery's `innerHeight` value for an element. This
@@ -8023,9 +8031,9 @@
/**
* Access dimensions and position of the first Element's content + padding +
* border box in this list.
- *
+ *
* This returns a rectangle with the dimenions actually available for content
- * in this element, in pixels, regardless of this element's box-sizing
+ * in this element, in pixels, regardless of this element's box-sizing
* property. Unlike [getBoundingClientRect], the dimensions of this rectangle
* will return the same numerical height if the element is hidden or not. This
* can be used to retrieve jQuery's `outerHeight` value for an element.
@@ -8036,9 +8044,9 @@
/**
* Access dimensions and position of the first Element's content + padding +
* border + margin box in this list.
- *
+ *
* This returns a rectangle with the dimenions actually available for content
- * in this element, in pixels, regardless of this element's box-sizing
+ * in this element, in pixels, regardless of this element's box-sizing
* property. Unlike [getBoundingClientRect], the dimensions of this rectangle
* will return the same numerical height if the element is hidden or not. This
* can be used to retrieve jQuery's `outerHeight` value for an element.
@@ -8084,12 +8092,15 @@
CssClassSet get classes => new _MultiElementCssClassSet(_elementList);
+ CssStyleDeclarationBase get style =>
+ new _CssStyleDeclarationSet(_elementList);
+
void set classes(Iterable<String> value) {
_elementList.forEach((e) => e.classes = value);
}
CssRect get contentEdge => new _ContentCssListRect(_elementList);
-
+
CssRect get paddingEdge => _elementList.first.paddingEdge;
CssRect get borderEdge => _elementList.first.borderEdge;
@@ -8740,13 +8751,13 @@
}
/**
- * Creates an instance of the template, using the provided model and binding
- * delegate.
+ * Creates an instance of the template, using the provided model and optional
+ * binding delegate.
*
* This is only supported if [isTemplate] is true.
*/
@Experimental()
- DocumentFragment createInstance(model, BindingDelegate delegate) {
+ DocumentFragment createInstance(model, [BindingDelegate delegate]) {
_ensureTemplate();
return TemplateElement.mdvPackage(this).createInstance(model, delegate);
}
@@ -8822,35 +8833,35 @@
/**
* Access this element's content position.
- *
+ *
* This returns a rectangle with the dimenions actually available for content
- * in this element, in pixels, regardless of this element's box-sizing
+ * in this element, in pixels, regardless of this element's box-sizing
* property. Unlike [getBoundingClientRect], the dimensions of this rectangle
* will return the same numerical height if the element is hidden or not.
- *
+ *
* _Important_ _note_: use of this method _will_ perform CSS calculations that
- * can trigger a browser reflow. Therefore, use of this property _during_ an
- * animation frame is discouraged. See also:
+ * can trigger a browser reflow. Therefore, use of this property _during_ an
+ * animation frame is discouraged. See also:
* [Browser Reflow](https://developers.google.com/speed/articles/reflow)
*/
@Experimental()
CssRect get contentEdge => new _ContentCssRect(this);
-
+
/**
* Access the dimensions and position of this element's content + padding box.
- *
+ *
* This returns a rectangle with the dimenions actually available for content
- * in this element, in pixels, regardless of this element's box-sizing
+ * in this element, in pixels, regardless of this element's box-sizing
* property. Unlike [getBoundingClientRect], the dimensions of this rectangle
* will return the same numerical height if the element is hidden or not. This
* can be used to retrieve jQuery's
- * [innerHeight](http://api.jquery.com/innerHeight/) value for an element.
+ * [innerHeight](http://api.jquery.com/innerHeight/) value for an element.
* This is also a rectangle equalling the dimensions of clientHeight and
* clientWidth.
- *
+ *
* _Important_ _note_: use of this method _will_ perform CSS calculations that
- * can trigger a browser reflow. Therefore, use of this property _during_ an
- * animation frame is discouraged. See also:
+ * can trigger a browser reflow. Therefore, use of this property _during_ an
+ * animation frame is discouraged. See also:
* [Browser Reflow](https://developers.google.com/speed/articles/reflow)
*/
@Experimental()
@@ -8859,17 +8870,17 @@
/**
* Access the dimensions and position of this element's content + padding +
* border box.
- *
+ *
* This returns a rectangle with the dimenions actually available for content
- * in this element, in pixels, regardless of this element's box-sizing
+ * in this element, in pixels, regardless of this element's box-sizing
* property. Unlike [getBoundingClientRect], the dimensions of this rectangle
* will return the same numerical height if the element is hidden or not. This
* can be used to retrieve jQuery's
* [outerHeight](http://api.jquery.com/outerHeight/) value for an element.
- *
- * _Important_ _note_: use of this method _will_ perform CSS calculations that
- * can trigger a browser reflow. Therefore, use of this property _during_ an
- * animation frame is discouraged. See also:
+ *
+ * _Important_ _note_: use of this method _will_ perform CSS calculations that
+ * can trigger a browser reflow. Therefore, use of this property _during_ an
+ * animation frame is discouraged. See also:
* [Browser Reflow](https://developers.google.com/speed/articles/reflow)
*/
@Experimental()
@@ -8878,38 +8889,38 @@
/**
* Access the dimensions and position of this element's content + padding +
* border + margin box.
- *
+ *
* This returns a rectangle with the dimenions actually available for content
- * in this element, in pixels, regardless of this element's box-sizing
+ * in this element, in pixels, regardless of this element's box-sizing
* property. Unlike [getBoundingClientRect], the dimensions of this rectangle
* will return the same numerical height if the element is hidden or not. This
* can be used to retrieve jQuery's
* [outerHeight](http://api.jquery.com/outerHeight/) value for an element.
- *
+ *
* _Important_ _note_: use of this method will perform CSS calculations that
- * can trigger a browser reflow. Therefore, use of this property _during_ an
- * animation frame is discouraged. See also:
+ * can trigger a browser reflow. Therefore, use of this property _during_ an
+ * animation frame is discouraged. See also:
* [Browser Reflow](https://developers.google.com/speed/articles/reflow)
*/
@Experimental()
CssRect get marginEdge => new _MarginCssRect(this);
- /**
- * Provides the coordinates of the element relative to the top of the
- * document.
+ /**
+ * Provides the coordinates of the element relative to the top of the
+ * document.
*
- * This method is the Dart equivalent to jQuery's
+ * This method is the Dart equivalent to jQuery's
* [offset](http://api.jquery.com/offset/) method.
*/
Point get documentOffset => offsetTo(document.documentElement);
- /**
+ /**
* Provides the offset of this element's [borderEdge] relative to the
* specified [parent].
- *
+ *
* This is the Dart equivalent of jQuery's
* [position](http://api.jquery.com/position/) method. Unlike jQuery's
- * position, however, [parent] can be any parent element of `this`,
+ * position, however, [parent] can be any parent element of `this`,
* rather than only `this`'s immediate [offsetParent]. If the specified
* element is _not_ an offset parent or transitive offset parent to this
* element, an [ArgumentError] is thrown.
@@ -8920,7 +8931,7 @@
static Point _offsetToHelper(Element current, Element parent) {
// We're hopping from _offsetParent_ to offsetParent (not just parent), so
- // offsetParent, "tops out" at BODY. But people could conceivably pass in
+ // offsetParent, "tops out" at BODY. But people could conceivably pass in
// the document.documentElement and I want it to return an absolute offset,
// so we have the special case checking for HTML.
bool foundAsParent = identical(current, parent) || parent.tagName == 'HTML';
@@ -8928,7 +8939,7 @@
if (foundAsParent) return new Point(0, 0);
throw new ArgumentError("Specified element is not a transitive offset "
"parent of this element.");
- }
+ }
Element parentOffset = current.offsetParent;
Point p = Element._offsetToHelper(parentOffset, parent);
return new Point(p.x + current.offsetLeft, p.y + current.offsetTop);
diff --git a/sdk/lib/html/dartium/html_dartium.dart b/sdk/lib/html/dartium/html_dartium.dart
index d667804..555a0d0 100644
--- a/sdk/lib/html/dartium/html_dartium.dart
+++ b/sdk/lib/html/dartium/html_dartium.dart
@@ -281,39 +281,6 @@
@DocsEditable()
-@DomName('ANGLEInstancedArrays')
-@Experimental() // untriaged
-class AngleInstancedArrays extends NativeFieldWrapperClass1 {
-
- @DomName('ANGLEInstancedArrays.VERTEX_ATTRIB_ARRAY_DIVISOR_ANGLE')
- @DocsEditable()
- @Experimental() // untriaged
- static const int VERTEX_ATTRIB_ARRAY_DIVISOR_ANGLE = 0x88FE;
-
- @DomName('ANGLEInstancedArrays.drawArraysInstancedANGLE')
- @DocsEditable()
- @Experimental() // untriaged
- void drawArraysInstancedAngle(int mode, int first, int count, int primcount) native "ANGLEInstancedArrays_drawArraysInstancedANGLE_Callback";
-
- @DomName('ANGLEInstancedArrays.drawElementsInstancedANGLE')
- @DocsEditable()
- @Experimental() // untriaged
- void drawElementsInstancedAngle(int mode, int count, int type, int offset, int primcount) native "ANGLEInstancedArrays_drawElementsInstancedANGLE_Callback";
-
- @DomName('ANGLEInstancedArrays.vertexAttribDivisorANGLE')
- @DocsEditable()
- @Experimental() // untriaged
- void vertexAttribDivisorAngle(int index, int divisor) native "ANGLEInstancedArrays_vertexAttribDivisorANGLE_Callback";
-
-}
-// Copyright (c) 2012, 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.
-
-// WARNING: Do not edit - generated code.
-
-
-@DocsEditable()
@DomName('WebKitAnimationEvent')
@SupportedBrowser(SupportedBrowser.CHROME)
@SupportedBrowser(SupportedBrowser.SAFARI)
@@ -3128,7 +3095,8 @@
@DomName('CSSStyleDeclaration')
-class CssStyleDeclaration extends NativeFieldWrapperClass1 {
+ class CssStyleDeclaration extends NativeFieldWrapperClass1 with
+ CssStyleDeclarationBase {
factory CssStyleDeclaration() => new CssStyleDeclaration.css('');
factory CssStyleDeclaration.css(String css) {
@@ -3136,7 +3104,24 @@
style.cssText = css;
return style;
}
+
+ String getPropertyValue(String propertyName) {
+ var propValue = _getPropertyValue(propertyName);
+ return propValue != null ? propValue : '';
+ }
+ @DomName('CSSStyleDeclaration.setProperty')
+ void setProperty(String propertyName, String value, [String priority]) {
+ if (priority == null) {
+ priority = '';
+ }
+ _setProperty(propertyName, value, priority);
+ }
+
+ /**
+ * Checks to see if CSS Transitions are supported.
+ */
+ static bool get supportsTransitions => true;
@DomName('CSSStyleDeclaration.cssText')
@DocsEditable()
@@ -3178,24 +3163,35 @@
@DocsEditable()
void _setProperty(String propertyName, String value, String priority) native "CSSStyleDeclaration_setProperty_Callback";
+}
- String getPropertyValue(String propertyName) {
- var propValue = _getPropertyValue(propertyName);
- return propValue != null ? propValue : '';
+class _CssStyleDeclarationSet extends Object with CssStyleDeclarationBase {
+ final Iterable<Element> _elementIterable;
+ Iterable<CssStyleDeclaration> _elementCssStyleDeclarationSetIterable;
+
+ _CssStyleDeclarationSet(this._elementIterable) {
+ _elementCssStyleDeclarationSetIterable = new List.from(
+ _elementIterable).map((e) => e.style);
}
- /**
- * Checks to see if CSS Transitions are supported.
- */
- static bool get supportsTransitions => true;
+ String getPropertyValue(String propertyName) =>
+ _elementCssStyleDeclarationSetIterable.first.getPropertyValue(
+ propertyName);
- @DomName('CSSStyleDeclaration.setProperty')
void setProperty(String propertyName, String value, [String priority]) {
- if (priority == null) {
- priority = '';
- }
- _setProperty(propertyName, value, priority);
+ _elementCssStyleDeclarationSetIterable.forEach((e) =>
+ e.setProperty(propertyName, value, priority));
}
+ // Important note: CssStyleDeclarationSet does NOT implement every method
+ // available in CssStyleDeclaration. Some of the methods don't make so much
+ // sense in terms of having a resonable value to return when you're
+ // considering a list of Elements. You will need to manually add any of the
+ // items in the MEMBERS set if you want that functionality.
+}
+
+abstract class CssStyleDeclarationBase {
+ String getPropertyValue(String propertyName);
+ void setProperty(String propertyName, String value, [String priority]);
// TODO(jacobr): generate this list of properties using the existing script.
/** Gets the value of "align-content" */
@@ -8487,7 +8483,7 @@
/**
* An immutable list containing HTML elements. This list contains some
- * additional methods when compared to regular lists for ease of CSS
+ * additional methods when compared to regular lists for ease of CSS
* manipulation on a group of elements.
*/
abstract class ElementList<T extends Element> extends ListBase<T> {
@@ -8506,28 +8502,40 @@
/** Replace the classes with `value` for every element in this list. */
set classes(Iterable<String> value);
- /**
+ /**
+ * Access the union of all [CssStyleDeclaration]s that are associated with an
+ * [ElementList].
+ *
+ * Grouping the style objects all together provides easy editing of specific
+ * properties of a collection of elements. Setting a specific property value
+ * will set that property in all [Element]s in the [ElementList]. Getting a
+ * specific property value will return the value of the property of the first
+ * element in the [ElementList].
+ */
+ CssStyleDeclarationBase get style;
+
+ /**
* Access dimensions and position of the Elements in this list.
- *
+ *
* Setting the height or width properties will set the height or width
- * property for all elements in the list. This returns a rectangle with the
+ * property for all elements in the list. This returns a rectangle with the
* dimenions actually available for content
- * in this element, in pixels, regardless of this element's box-sizing
+ * in this element, in pixels, regardless of this element's box-sizing
* property. Getting the height or width returns the height or width of the
- * first Element in this list.
+ * first Element in this list.
*
* Unlike [getBoundingClientRect], the dimensions of this rectangle
* will return the same numerical height if the element is hidden or not.
*/
@Experimental()
CssRect get contentEdge;
-
+
/**
* Access dimensions and position of the first Element's content + padding box
* in this list.
- *
+ *
* This returns a rectangle with the dimenions actually available for content
- * in this element, in pixels, regardless of this element's box-sizing
+ * in this element, in pixels, regardless of this element's box-sizing
* property. Unlike [getBoundingClientRect], the dimensions of this rectangle
* will return the same numerical height if the element is hidden or not. This
* can be used to retrieve jQuery's `innerHeight` value for an element. This
@@ -8540,9 +8548,9 @@
/**
* Access dimensions and position of the first Element's content + padding +
* border box in this list.
- *
+ *
* This returns a rectangle with the dimenions actually available for content
- * in this element, in pixels, regardless of this element's box-sizing
+ * in this element, in pixels, regardless of this element's box-sizing
* property. Unlike [getBoundingClientRect], the dimensions of this rectangle
* will return the same numerical height if the element is hidden or not. This
* can be used to retrieve jQuery's `outerHeight` value for an element.
@@ -8553,9 +8561,9 @@
/**
* Access dimensions and position of the first Element's content + padding +
* border + margin box in this list.
- *
+ *
* This returns a rectangle with the dimenions actually available for content
- * in this element, in pixels, regardless of this element's box-sizing
+ * in this element, in pixels, regardless of this element's box-sizing
* property. Unlike [getBoundingClientRect], the dimensions of this rectangle
* will return the same numerical height if the element is hidden or not. This
* can be used to retrieve jQuery's `outerHeight` value for an element.
@@ -8601,12 +8609,15 @@
CssClassSet get classes => new _MultiElementCssClassSet(_elementList);
+ CssStyleDeclarationBase get style =>
+ new _CssStyleDeclarationSet(_elementList);
+
void set classes(Iterable<String> value) {
_elementList.forEach((e) => e.classes = value);
}
CssRect get contentEdge => new _ContentCssListRect(_elementList);
-
+
CssRect get paddingEdge => _elementList.first.paddingEdge;
CssRect get borderEdge => _elementList.first.borderEdge;
@@ -9108,13 +9119,13 @@
}
/**
- * Creates an instance of the template, using the provided model and binding
- * delegate.
+ * Creates an instance of the template, using the provided model and optional
+ * binding delegate.
*
* This is only supported if [isTemplate] is true.
*/
@Experimental()
- DocumentFragment createInstance(model, BindingDelegate delegate) {
+ DocumentFragment createInstance(model, [BindingDelegate delegate]) {
_ensureTemplate();
return TemplateElement.mdvPackage(this).createInstance(model, delegate);
}
@@ -9190,35 +9201,35 @@
/**
* Access this element's content position.
- *
+ *
* This returns a rectangle with the dimenions actually available for content
- * in this element, in pixels, regardless of this element's box-sizing
+ * in this element, in pixels, regardless of this element's box-sizing
* property. Unlike [getBoundingClientRect], the dimensions of this rectangle
* will return the same numerical height if the element is hidden or not.
- *
+ *
* _Important_ _note_: use of this method _will_ perform CSS calculations that
- * can trigger a browser reflow. Therefore, use of this property _during_ an
- * animation frame is discouraged. See also:
+ * can trigger a browser reflow. Therefore, use of this property _during_ an
+ * animation frame is discouraged. See also:
* [Browser Reflow](https://developers.google.com/speed/articles/reflow)
*/
@Experimental()
CssRect get contentEdge => new _ContentCssRect(this);
-
+
/**
* Access the dimensions and position of this element's content + padding box.
- *
+ *
* This returns a rectangle with the dimenions actually available for content
- * in this element, in pixels, regardless of this element's box-sizing
+ * in this element, in pixels, regardless of this element's box-sizing
* property. Unlike [getBoundingClientRect], the dimensions of this rectangle
* will return the same numerical height if the element is hidden or not. This
* can be used to retrieve jQuery's
- * [innerHeight](http://api.jquery.com/innerHeight/) value for an element.
+ * [innerHeight](http://api.jquery.com/innerHeight/) value for an element.
* This is also a rectangle equalling the dimensions of clientHeight and
* clientWidth.
- *
+ *
* _Important_ _note_: use of this method _will_ perform CSS calculations that
- * can trigger a browser reflow. Therefore, use of this property _during_ an
- * animation frame is discouraged. See also:
+ * can trigger a browser reflow. Therefore, use of this property _during_ an
+ * animation frame is discouraged. See also:
* [Browser Reflow](https://developers.google.com/speed/articles/reflow)
*/
@Experimental()
@@ -9227,17 +9238,17 @@
/**
* Access the dimensions and position of this element's content + padding +
* border box.
- *
+ *
* This returns a rectangle with the dimenions actually available for content
- * in this element, in pixels, regardless of this element's box-sizing
+ * in this element, in pixels, regardless of this element's box-sizing
* property. Unlike [getBoundingClientRect], the dimensions of this rectangle
* will return the same numerical height if the element is hidden or not. This
* can be used to retrieve jQuery's
* [outerHeight](http://api.jquery.com/outerHeight/) value for an element.
- *
- * _Important_ _note_: use of this method _will_ perform CSS calculations that
- * can trigger a browser reflow. Therefore, use of this property _during_ an
- * animation frame is discouraged. See also:
+ *
+ * _Important_ _note_: use of this method _will_ perform CSS calculations that
+ * can trigger a browser reflow. Therefore, use of this property _during_ an
+ * animation frame is discouraged. See also:
* [Browser Reflow](https://developers.google.com/speed/articles/reflow)
*/
@Experimental()
@@ -9246,38 +9257,38 @@
/**
* Access the dimensions and position of this element's content + padding +
* border + margin box.
- *
+ *
* This returns a rectangle with the dimenions actually available for content
- * in this element, in pixels, regardless of this element's box-sizing
+ * in this element, in pixels, regardless of this element's box-sizing
* property. Unlike [getBoundingClientRect], the dimensions of this rectangle
* will return the same numerical height if the element is hidden or not. This
* can be used to retrieve jQuery's
* [outerHeight](http://api.jquery.com/outerHeight/) value for an element.
- *
+ *
* _Important_ _note_: use of this method will perform CSS calculations that
- * can trigger a browser reflow. Therefore, use of this property _during_ an
- * animation frame is discouraged. See also:
+ * can trigger a browser reflow. Therefore, use of this property _during_ an
+ * animation frame is discouraged. See also:
* [Browser Reflow](https://developers.google.com/speed/articles/reflow)
*/
@Experimental()
CssRect get marginEdge => new _MarginCssRect(this);
- /**
- * Provides the coordinates of the element relative to the top of the
- * document.
+ /**
+ * Provides the coordinates of the element relative to the top of the
+ * document.
*
- * This method is the Dart equivalent to jQuery's
+ * This method is the Dart equivalent to jQuery's
* [offset](http://api.jquery.com/offset/) method.
*/
Point get documentOffset => offsetTo(document.documentElement);
- /**
+ /**
* Provides the offset of this element's [borderEdge] relative to the
* specified [parent].
- *
+ *
* This is the Dart equivalent of jQuery's
* [position](http://api.jquery.com/position/) method. Unlike jQuery's
- * position, however, [parent] can be any parent element of `this`,
+ * position, however, [parent] can be any parent element of `this`,
* rather than only `this`'s immediate [offsetParent]. If the specified
* element is _not_ an offset parent or transitive offset parent to this
* element, an [ArgumentError] is thrown.
@@ -9288,7 +9299,7 @@
static Point _offsetToHelper(Element current, Element parent) {
// We're hopping from _offsetParent_ to offsetParent (not just parent), so
- // offsetParent, "tops out" at BODY. But people could conceivably pass in
+ // offsetParent, "tops out" at BODY. But people could conceivably pass in
// the document.documentElement and I want it to return an absolute offset,
// so we have the special case checking for HTML.
bool foundAsParent = identical(current, parent) || parent.tagName == 'HTML';
@@ -9296,7 +9307,7 @@
if (foundAsParent) return new Point(0, 0);
throw new ArgumentError("Specified element is not a transitive offset "
"parent of this element.");
- }
+ }
Element parentOffset = current.offsetParent;
Point p = Element._offsetToHelper(parentOffset, parent);
return new Point(p.x + current.offsetLeft, p.y + current.offsetTop);
diff --git a/sdk/lib/io/directory_impl.dart b/sdk/lib/io/directory_impl.dart
index 5429a29..17d67be 100644
--- a/sdk/lib/io/directory_impl.dart
+++ b/sdk/lib/io/directory_impl.dart
@@ -14,7 +14,16 @@
static const LIST_STOP_REQUEST = 6;
static const RENAME_REQUEST = 7;
- _Directory(String this._path);
+ final String path;
+ SendPort _directoryService;
+
+ _Directory(String this.path) {
+ if (path is! String) {
+ throw new ArgumentError('${Error.safeToString(path)} '
+ 'is not a String');
+ }
+ }
+
_Directory.fromPath(Path path) : this(path.toNativePath());
external static String _current();
@@ -43,7 +52,7 @@
_ensureDirectoryService();
List request = new List(2);
request[0] = EXISTS_REQUEST;
- request[1] = _path;
+ request[1] = path;
return _directoryService.call(request).then((response) {
if (_isErrorResponse(response)) {
throw _exceptionOrErrorFromResponse(response, "Exists failed");
@@ -53,12 +62,9 @@
}
bool existsSync() {
- if (_path is !String) {
- throw new ArgumentError();
- }
- var result = _exists(_path);
+ var result = _exists(path);
if (result is OSError) {
- throw new DirectoryException("Exists failed", _path, result);
+ throw new DirectoryException("Exists failed", path, result);
}
return (result == 1);
}
@@ -92,10 +98,7 @@
}
Future<Directory> createRecursively() {
- if (_path is !String) {
- throw new ArgumentError();
- }
- var path = new Path(_path);
+ var path = new Path(path);
var dirsToCreate = [];
var terminator = path.isAbsolute ? '/' : '';
while (path.toString() != terminator) {
@@ -126,7 +129,7 @@
_ensureDirectoryService();
List request = new List(2);
request[0] = CREATE_REQUEST;
- request[1] = _path;
+ request[1] = path;
return _directoryService.call(request).then((response) {
if (_isErrorResponse(response)) {
throw _exceptionOrErrorFromResponse(response, "Creation failed");
@@ -136,7 +139,7 @@
}
void createRecursivelySync() {
- var path = new Path(_path);
+ var path = new Path(path);
var dirsToCreate = [];
var terminator = path.isAbsolute ? '/' : '';
while (path.toString() != terminator) {
@@ -151,13 +154,10 @@
}
void createSync({recursive: false}) {
- if (_path is !String) {
- throw new ArgumentError();
- }
if (recursive) return createRecursivelySync();
- var result = _create(_path);
+ var result = _create(path);
if (result is OSError) {
- throw new DirectoryException("Creation failed", _path, result);
+ throw new DirectoryException("Creation failed", path, result);
}
}
@@ -165,7 +165,7 @@
_ensureDirectoryService();
List request = new List(2);
request[0] = CREATE_TEMP_REQUEST;
- request[1] = _path;
+ request[1] = path;
return _directoryService.call(request).then((response) {
if (_isErrorResponse(response)) {
throw _exceptionOrErrorFromResponse(
@@ -176,13 +176,10 @@
}
Directory createTempSync() {
- if (_path is !String) {
- throw new ArgumentError();
- }
var result = _createTemp(path);
if (result is OSError) {
throw new DirectoryException("Creation of temporary directory failed",
- _path,
+ path,
result);
}
return new Directory(result);
@@ -192,7 +189,7 @@
_ensureDirectoryService();
List request = new List(3);
request[0] = DELETE_REQUEST;
- request[1] = _path;
+ request[1] = path;
request[2] = recursive;
return _directoryService.call(request).then((response) {
if (_isErrorResponse(response)) {
@@ -203,12 +200,9 @@
}
void deleteSync({recursive: false}) {
- if (_path is !String) {
- throw new ArgumentError();
- }
- var result = _delete(_path, recursive);
+ var result = _delete(path, recursive);
if (result is OSError) {
- throw new DirectoryException("Deletion failed", _path, result);
+ throw new DirectoryException("Deletion failed", path, result);
}
}
@@ -216,7 +210,7 @@
_ensureDirectoryService();
List request = new List(3);
request[0] = RENAME_REQUEST;
- request[1] = _path;
+ request[1] = path;
request[2] = newPath;
return _directoryService.call(request).then((response) {
if (_isErrorResponse(response)) {
@@ -227,12 +221,12 @@
}
Directory renameSync(String newPath) {
- if (_path is !String || newPath is !String) {
+ if (newPath is !String) {
throw new ArgumentError();
}
- var result = _rename(_path, newPath);
+ var result = _rename(path, newPath);
if (result is OSError) {
- throw new DirectoryException("Rename failed", _path, result);
+ throw new DirectoryException("Rename failed", path, result);
}
return new Directory(newPath);
}
@@ -262,14 +256,12 @@
}
List listSync({bool recursive: false, bool followLinks: true}) {
- if (_path is! String || recursive is! bool || followLinks is! bool) {
+ if (recursive is! bool || followLinks is! bool) {
throw new ArgumentError();
}
return _list(_trimTrailingPathSeparators(path), recursive, followLinks);
}
- String get path => _path;
-
String toString() => "Directory: '$path'";
bool _isErrorResponse(response) {
@@ -284,7 +276,7 @@
case _OSERROR_RESPONSE:
var err = new OSError(response[_OSERROR_RESPONSE_MESSAGE],
response[_OSERROR_RESPONSE_ERROR_CODE]);
- return new DirectoryException(message, _path, err);
+ return new DirectoryException(message, path, err);
default:
return new Exception("Unknown error");
}
@@ -295,9 +287,6 @@
_directoryService = _newServicePort();
}
}
-
- final String _path;
- SendPort _directoryService;
}
class _AsyncDirectoryLister {
diff --git a/sdk/lib/io/file_impl.dart b/sdk/lib/io/file_impl.dart
index 0789990..b6a47c79 100644
--- a/sdk/lib/io/file_impl.dart
+++ b/sdk/lib/io/file_impl.dart
@@ -235,10 +235,13 @@
// Class for encapsulating the native implementation of files.
class _File implements File {
+ final String path;
+ SendPort _fileService;
+
// Constructor for file.
- _File(String this._path) {
- if (_path is! String) {
- throw new ArgumentError('${Error.safeToString(_path)} '
+ _File(String this.path) {
+ if (path is! String) {
+ throw new ArgumentError('${Error.safeToString(path)} '
'is not a String');
}
}
@@ -250,10 +253,10 @@
_ensureFileService();
List request = new List(2);
request[0] = _EXISTS_REQUEST;
- request[1] = _path;
+ request[1] = path;
return _fileService.call(request).then((response) {
if (_isErrorResponse(response)) {
- throw _exceptionFromResponse(response, "Cannot check existence", _path);
+ throw _exceptionFromResponse(response, "Cannot check existence", path);
}
return response;
});
@@ -262,8 +265,8 @@
external static _exists(String path);
bool existsSync() {
- var result = _exists(_path);
- throwIfError(result, "Cannot check existence of file", _path);
+ var result = _exists(path);
+ throwIfError(result, "Cannot check existence of file", path);
return result;
}
@@ -275,10 +278,10 @@
_ensureFileService();
List request = new List(2);
request[0] = _CREATE_REQUEST;
- request[1] = _path;
+ request[1] = path;
return _fileService.call(request).then((response) {
if (_isErrorResponse(response)) {
- throw _exceptionFromResponse(response, "Cannot create file", _path);
+ throw _exceptionFromResponse(response, "Cannot create file", path);
}
return this;
});
@@ -291,18 +294,18 @@
external static _linkTarget(String path);
void createSync() {
- var result = _create(_path);
- throwIfError(result, "Cannot create file", _path);
+ var result = _create(path);
+ throwIfError(result, "Cannot create file", path);
}
Future<File> delete() {
_ensureFileService();
List request = new List(2);
request[0] = _DELETE_REQUEST;
- request[1] = _path;
+ request[1] = path;
return _fileService.call(request).then((response) {
if (_isErrorResponse(response)) {
- throw _exceptionFromResponse(response, "Cannot delete file", _path);
+ throw _exceptionFromResponse(response, "Cannot delete file", path);
}
return this;
});
@@ -313,20 +316,20 @@
external static _deleteLink(String path);
void deleteSync() {
- var result = _delete(_path);
- throwIfError(result, "Cannot delete file", _path);
+ var result = _delete(path);
+ throwIfError(result, "Cannot delete file", path);
}
Future<File> rename(String newPath) {
_ensureFileService();
List request = new List(3);
request[0] = _RENAME_REQUEST;
- request[1] = _path;
+ request[1] = path;
request[2] = newPath;
return _fileService.call(request).then((response) {
if (_isErrorResponse(response)) {
throw _exceptionFromResponse(
- response, "Cannot rename file to '$newPath'", _path);
+ response, "Cannot rename file to '$newPath'", path);
}
return new File(newPath);
});
@@ -337,13 +340,13 @@
external static _renameLink(String oldPath, String newPath);
File renameSync(String newPath) {
- var result = _rename(_path, newPath);
- throwIfError(result, "Cannot rename file to '$newPath'", _path);
+ var result = _rename(path, newPath);
+ throwIfError(result, "Cannot rename file to '$newPath'", path);
return new File(newPath);
}
Directory get directory {
- Path path = new Path(_path).directoryPath;
+ Path path = new Path(path).directoryPath;
return new Directory.fromPath(path);
}
@@ -356,13 +359,13 @@
}
List request = new List(3);
request[0] = _OPEN_REQUEST;
- request[1] = _path;
+ request[1] = path;
request[2] = mode._mode; // Direct int value for serialization.
return _fileService.call(request).then((response) {
if (_isErrorResponse(response)) {
- throw _exceptionFromResponse(response, "Cannot open file", _path);
+ throw _exceptionFromResponse(response, "Cannot open file", path);
}
- return new _RandomAccessFile(response, _path);
+ return new _RandomAccessFile(response, path);
});
}
@@ -370,12 +373,12 @@
_ensureFileService();
List request = new List(2);
request[0] = _LENGTH_FROM_PATH_REQUEST;
- request[1] = _path;
+ request[1] = path;
return _fileService.call(request).then((response) {
if (_isErrorResponse(response)) {
throw _exceptionFromResponse(response,
"Cannot retrieve length of file",
- _path);
+ path);
}
return response;
});
@@ -385,8 +388,8 @@
external static _lengthFromPath(String path);
int lengthSync() {
- var result = _lengthFromPath(_path);
- throwIfError(result, "Cannot retrieve length of file", _path);
+ var result = _lengthFromPath(path);
+ throwIfError(result, "Cannot retrieve length of file", path);
return result;
}
@@ -394,12 +397,12 @@
_ensureFileService();
List request = new List(2);
request[0] = _LAST_MODIFIED_REQUEST;
- request[1] = _path;
+ request[1] = path;
return _fileService.call(request).then((response) {
if (_isErrorResponse(response)) {
throw _exceptionFromResponse(response,
"Cannot retrieve modification time",
- _path);
+ path);
}
return new DateTime.fromMillisecondsSinceEpoch(response);
});
@@ -409,7 +412,7 @@
DateTime lastModifiedSync() {
var ms = _lastModified(path);
- throwIfError(ms, "Cannot retrieve modification time", _path);
+ throwIfError(ms, "Cannot retrieve modification time", path);
return new DateTime.fromMillisecondsSinceEpoch(ms);
}
@@ -421,11 +424,11 @@
mode != FileMode.APPEND) {
throw new FileException("Unknown file mode. Use FileMode.READ, "
"FileMode.WRITE or FileMode.APPEND.",
- _path);
+ path);
}
- var id = _open(_path, mode._mode);
- throwIfError(id, "Cannot open file", _path);
- return new _RandomAccessFile(id, _path);
+ var id = _open(path, mode._mode);
+ throwIfError(id, "Cannot open file", path);
+ return new _RandomAccessFile(id, path);
}
external static int _openStdio(int fd);
@@ -442,12 +445,12 @@
_ensureFileService();
List request = new List(2);
request[0] = _FULL_PATH_REQUEST;
- request[1] = _path;
+ request[1] = path;
return _fileService.call(request).then((response) {
if (_isErrorResponse(response)) {
throw _exceptionFromResponse(response,
"Cannot retrieve full path",
- _path);
+ path);
}
return response;
});
@@ -456,13 +459,13 @@
external static _fullPath(String path);
String fullPathSync() {
- var result = _fullPath(_path);
- throwIfError(result, "Cannot retrieve full path", _path);
+ var result = _fullPath(path);
+ throwIfError(result, "Cannot retrieve full path", path);
return result;
}
Stream<List<int>> openRead([int start, int end]) {
- return new _FileStream(_path, start, end);
+ return new _FileStream(path, start, end);
}
IOSink openWrite({FileMode mode: FileMode.WRITE,
@@ -573,8 +576,6 @@
writeAsBytesSync(_encodeString(contents, encoding), mode: mode);
}
- String get path => _path;
-
String toString() => "File: '$path'";
void _ensureFileService() {
@@ -588,15 +589,15 @@
throw new FileException(msg, path, result);
}
}
-
- final String _path;
-
- SendPort _fileService;
}
class _RandomAccessFile implements RandomAccessFile {
- _RandomAccessFile(int this._id, String this._path);
+ final String path;
+ int _id;
+ SendPort _fileService;
+
+ _RandomAccessFile(int this._id, String this.path);
Future<RandomAccessFile> close() {
if (closed) return _closedException();
@@ -612,7 +613,7 @@
_id = result;
return this;
} else {
- throw new FileException("Cannot close file", _path);
+ throw new FileException("Cannot close file", path);
}
});
}
@@ -623,7 +624,7 @@
_checkNotClosed();
var id = _close(_id);
if (id == -1) {
- throw new FileException("Cannot close file", _path);
+ throw new FileException("Cannot close file", path);
}
_id = id;
}
@@ -636,7 +637,7 @@
request[1] = _id;
return _fileService.call(request).then((response) {
if (_isErrorResponse(response)) {
- throw _exceptionFromResponse(response, "readByte failed", _path);
+ throw _exceptionFromResponse(response, "readByte failed", path);
}
return response;
});
@@ -648,7 +649,7 @@
_checkNotClosed();
var result = _readByte(_id);
if (result is OSError) {
- throw new FileException("readByte failed", _path, result);
+ throw new FileException("readByte failed", path, result);
}
return result;
}
@@ -665,7 +666,7 @@
request[2] = bytes;
return _fileService.call(request).then((response) {
if (_isErrorResponse(response)) {
- throw _exceptionFromResponse(response, "read failed", _path);
+ throw _exceptionFromResponse(response, "read failed", path);
}
return response[1];
});
@@ -680,7 +681,7 @@
}
var result = _read(_id, bytes);
if (result is OSError) {
- throw new FileException("readSync failed",_path, result);
+ throw new FileException("readSync failed", path, result);
}
return result;
}
@@ -701,7 +702,7 @@
request[2] = end - start;
return _fileService.call(request).then((response) {
if (_isErrorResponse(response)) {
- throw _exceptionFromResponse(response, "readInto failed", _path);
+ throw _exceptionFromResponse(response, "readInto failed", path);
}
var read = response[1];
var data = response[2];
@@ -733,7 +734,7 @@
_checkReadWriteListArguments(buffer.length, start, end);
var result = _readInto(_id, buffer, start, end);
if (result is OSError) {
- throw new FileException("readInto failed", _path, result);
+ throw new FileException("readInto failed", path, result);
}
return result;
}
@@ -750,7 +751,7 @@
request[2] = value;
return _fileService.call(request).then((response) {
if (_isErrorResponse(response)) {
- throw _exceptionFromResponse(response, "writeByte failed",_path);
+ throw _exceptionFromResponse(response, "writeByte failed", path);
}
return this;
});
@@ -765,7 +766,7 @@
}
var result = _writeByte(_id, value);
if (result is OSError) {
- throw new FileException("writeByte failed", _path, result);
+ throw new FileException("writeByte failed", path, result);
}
return result;
}
@@ -795,7 +796,7 @@
request[4] = end - (start - result.start);
return _fileService.call(request).then((response) {
if (_isErrorResponse(response)) {
- throw _exceptionFromResponse(response, "writeFrom failed", _path);
+ throw _exceptionFromResponse(response, "writeFrom failed", path);
}
return this;
});
@@ -821,7 +822,7 @@
bufferAndStart.start,
end - (start - bufferAndStart.start));
if (result is OSError) {
- throw new FileException("writeFrom failed", _path, result);
+ throw new FileException("writeFrom failed", path, result);
}
}
@@ -850,7 +851,7 @@
request[1] = _id;
return _fileService.call(request).then((response) {
if (_isErrorResponse(response)) {
- throw _exceptionFromResponse(response, "position failed", _path);
+ throw _exceptionFromResponse(response, "position failed", path);
}
return response;
});
@@ -862,7 +863,7 @@
_checkNotClosed();
var result = _position(_id);
if (result is OSError) {
- throw new FileException("position failed", _path, result);
+ throw new FileException("position failed", path, result);
}
return result;
}
@@ -876,7 +877,7 @@
request[2] = position;
return _fileService.call(request).then((response) {
if (_isErrorResponse(response)) {
- throw _exceptionFromResponse(response, "setPosition failed", _path);
+ throw _exceptionFromResponse(response, "setPosition failed", path);
}
return this;
});
@@ -888,7 +889,7 @@
_checkNotClosed();
var result = _setPosition(_id, position);
if (result is OSError) {
- throw new FileException("setPosition failed", _path, result);
+ throw new FileException("setPosition failed", path, result);
}
}
@@ -901,7 +902,7 @@
request[2] = length;
return _fileService.call(request).then((response) {
if (_isErrorResponse(response)) {
- throw _exceptionFromResponse(response, "truncate failed", _path);
+ throw _exceptionFromResponse(response, "truncate failed", path);
}
return this;
});
@@ -913,7 +914,7 @@
_checkNotClosed();
var result = _truncate(_id, length);
if (result is OSError) {
- throw new FileException("truncate failed", _path, result);
+ throw new FileException("truncate failed", path, result);
}
}
@@ -925,7 +926,7 @@
request[1] = _id;
return _fileService.call(request).then((response) {
if (_isErrorResponse(response)) {
- throw _exceptionFromResponse(response, "length failed", _path);
+ throw _exceptionFromResponse(response, "length failed", path);
}
return response;
});
@@ -937,7 +938,7 @@
_checkNotClosed();
var result = _length(_id);
if (result is OSError) {
- throw new FileException("length failed", _path, result);
+ throw new FileException("length failed", path, result);
}
return result;
}
@@ -952,7 +953,7 @@
if (_isErrorResponse(response)) {
throw _exceptionFromResponse(response,
"flush failed",
- _path);
+ path);
}
return this;
});
@@ -964,12 +965,10 @@
_checkNotClosed();
var result = _flush(_id);
if (result is OSError) {
- throw new FileException("flush failed", _path, result);
+ throw new FileException("flush failed", path, result);
}
}
- String get path => _path;
-
void _ensureFileService() {
if (_fileService == null) {
_fileService = _FileUtils._newServicePort();
@@ -980,16 +979,11 @@
void _checkNotClosed() {
if (closed) {
- throw new FileException("File closed", _path);
+ throw new FileException("File closed", path);
}
}
Future _closedException() {
- return new Future.error(new FileException("File closed", _path));
+ return new Future.error(new FileException("File closed", path));
}
-
- final String _path;
- int _id;
-
- SendPort _fileService;
}
diff --git a/sdk/lib/io/http.dart b/sdk/lib/io/http.dart
index 6764ab2..755c96c 100644
--- a/sdk/lib/io/http.dart
+++ b/sdk/lib/io/http.dart
@@ -497,7 +497,7 @@
*/
abstract class HeaderValue {
/**
- * Creates a new header value object setting the value part.
+ * Creates a new header value object setting the value and parameters.
*/
factory HeaderValue([String value = "", Map<String, String> parameters]) {
return new _HeaderValue(value, parameters);
@@ -519,6 +519,9 @@
/**
* Gets the map of parameters.
+ *
+ * This map cannot be modified. invoking any operation which would
+ * modify the map will throw [UnsupportedError].
*/
Map<String, String> get parameters;
@@ -940,12 +943,21 @@
factory HttpClient() => new _HttpClient();
/**
- * Opens a HTTP connection. The returned [HttpClientRequest] is used to
- * fill in the content of the request before sending it. The 'host' header for
- * the request will be set to the value [host]:[port]. This can be overridden
- * through the [HttpClientRequest] interface before the request is sent.
- * NOTE if [host] is an IP address this will still be set in the 'host'
+ * Opens a HTTP connection.
+ *
+ * The HTTP method to use is specified in [method], the server is
+ * specified using [host] and [port], and the path (including
+ * possible fragment and query) is specified using [path].
+ *
+ * The `Host` header for the request will be set to the value
+ * [host]:[port]. This can be overridden through the
+ * [HttpClientRequest] interface before the request is sent. NOTE
+ * if [host] is an IP address this will still be set in the `Host`
* header.
+ *
+ * For additional information on the sequence of events during an
+ * HTTP transaction, and the objects returned by the futures, see
+ * the overall documentation for the class [HttpClient].
*/
Future<HttpClientRequest> open(String method,
String host,
@@ -953,36 +965,60 @@
String path);
/**
- * Opens a HTTP connection. The returned [HttpClientRequest] is used to
- * fill in the content of the request before sending it. The 'hosth header for
- * the request will be set to the value [host]:[port]. This can be overridden
- * through the [HttpClientRequest] interface before the request is sent.
- * NOTE if [host] is an IP address this will still be set in the 'host'
+ * Opens a HTTP connection.
+ *
+ * The HTTP method is specified in [method] and the URL to use in
+ * [url].
+ *
+ * The `Host` header for the request will be set to the value
+ * [host]:[port]. This can be overridden through the
+ * [HttpClientRequest] interface before the request is sent. NOTE
+ * if [host] is an IP address this will still be set in the `Host`
* header.
+ *
+ * For additional information on the sequence of events during an
+ * HTTP transaction, and the objects returned by the futures, see
+ * the overall documentation for the class [HttpClient].
*/
Future<HttpClientRequest> openUrl(String method, Uri url);
/**
- * Opens a HTTP connection using the GET method. See [open] for
- * details. Using this method to open a HTTP connection will set the
- * content length to 0.
+ * Opens a HTTP connection using the GET method.
+ *
+ * The server is specified using [host] and [port], and the path
+ * (including possible fragment and query) is specified using
+ * [path].
+ *
+ * See [open] for details.
*/
Future<HttpClientRequest> get(String host, int port, String path);
/**
- * Opens a HTTP connection using the GET method. See [openUrl] for
- * details. Using this method to open a HTTP connection will set the
- * content length to 0.
+ * Opens a HTTP connection using the GET method.
+ *
+ * The URL to use is specified in [url].
+ *
+ * See [openUrl] for details.
*/
Future<HttpClientRequest> getUrl(Uri url);
/**
- * Opens a HTTP connection using the POST method. See [open] for details.
+ * Opens a HTTP connection using the POST method.
+ *
+ * The server is specified using [host] and [port], and the path
+ * (including possible fragment and query) is specified using
+ * [path].
+ *
+ * See [open] for details.
*/
Future<HttpClientRequest> post(String host, int port, String path);
/**
- * Opens a HTTP connection using the POST method. See [openUrl] for details.
+ * Opens a HTTP connection using the POST method.
+ *
+ * The URL to use is specified in [url].
+ *
+ * See [openUrl] for details.
*/
Future<HttpClientRequest> postUrl(Uri url);
diff --git a/sdk/lib/io/http_headers.dart b/sdk/lib/io/http_headers.dart
index eec66c6..b355aa0 100644
--- a/sdk/lib/io/http_headers.dart
+++ b/sdk/lib/io/http_headers.dart
@@ -473,9 +473,14 @@
class _HeaderValue implements HeaderValue {
String _value;
- Map<String, String> _parameters;
+ _UnmodifiableMap<String, String> _parameters;
- _HeaderValue([String this._value = "", this._parameters]);
+ _HeaderValue([String this._value = "", Map<String, String> parameters]) {
+ if (parameters != null) {
+ _parameters =
+ new _UnmodifiableMap(new Map<String, String>.from(parameters));
+ }
+ }
static _HeaderValue parse(String value, {parameterSeparator: ";"}) {
// Parse the string.
@@ -486,8 +491,14 @@
String get value => _value;
+ void _ensureParameters() {
+ if (_parameters == null) {
+ _parameters = new _UnmodifiableMap(new Map<String, String>());
+ }
+ }
+
Map<String, String> get parameters {
- if (_parameters == null) _parameters = new Map<String, String>();
+ _ensureParameters();
return _parameters;
}
@@ -540,7 +551,8 @@
}
void parseParameters() {
- _parameters = new Map<String, String>();
+ var parameters = new Map<String, String>();
+ _parameters = new _UnmodifiableMap(parameters);
String parseParameterName() {
int start = index;
@@ -584,7 +596,7 @@
expect("=");
skipWS();
String value = parseParameterValue();
- _parameters[name] = value;
+ parameters[name] = value;
skipWS();
if (done()) return;
expect(parameterSeparator);
@@ -612,14 +624,16 @@
: _primaryType = primaryType, _subType = subType, super("") {
if (_primaryType == null) _primaryType = "";
if (_subType == null) _subType = "";
- _value = "$_primaryType/$_subType";;
+ _value = "$_primaryType/$_subType";
if (parameters != null) {
+ _ensureParameters();
parameters.forEach((String key, String value) {
- this.parameters[key.toLowerCase()] = value.toLowerCase();
+ this._parameters._map[key.toLowerCase()] = value.toLowerCase();
});
}
if (charset != null) {
- this.parameters["charset"] = charset.toLowerCase();
+ _ensureParameters();
+ this._parameters._map["charset"] = charset.toLowerCase();
}
}
@@ -633,7 +647,8 @@
result._primaryType = result._value.trim().toLowerCase();
result._subType = "";
} else {
- result._primaryType = result._value.substring(0, index).trim().toLowerCase();
+ result._primaryType =
+ result._value.substring(0, index).trim().toLowerCase();
result._subType = result._value.substring(index + 1).trim().toLowerCase();
}
return result;
@@ -778,3 +793,34 @@
bool httpOnly = false;
bool secure = false;
}
+
+
+class _UnmodifiableMap<K, V> implements Map<K, V> {
+ final Map _map;
+ const _UnmodifiableMap(this._map);
+
+ bool containsValue(Object value) => _map.containsValue(value);
+ bool containsKey(Object key) => _map.containsKey(key);
+ V operator [](Object key) => _map[key];
+ void operator []=(K key, V value) {
+ throw new UnsupportedError("Cannot modify an unmodifiable map");
+ }
+ V putIfAbsent(K key, V ifAbsent()) {
+ throw new UnsupportedError("Cannot modify an unmodifiable map");
+ }
+ addAll(Map other) {
+ throw new UnsupportedError("Cannot modify an unmodifiable map");
+ }
+ V remove(Object key) {
+ throw new UnsupportedError("Cannot modify an unmodifiable map");
+ }
+ void clear() {
+ throw new UnsupportedError("Cannot modify an unmodifiable map");
+ }
+ void forEach(void f(K key, V value)) => _map.forEach(f);
+ Iterable<K> get keys => _map.keys;
+ Iterable<V> get values => _map.values;
+ int get length => _map.length;
+ bool get isEmpty => _map.isEmpty;
+ bool get isNotEmpty => _map.isNotEmpty;
+}
diff --git a/sdk/lib/io/link.dart b/sdk/lib/io/link.dart
index 237154d..8c28eb4 100644
--- a/sdk/lib/io/link.dart
+++ b/sdk/lib/io/link.dart
@@ -130,7 +130,13 @@
SendPort _fileService;
- _Link(String this.path);
+ _Link(String this.path) {
+ if (path is! String) {
+ throw new ArgumentError('${Error.safeToString(path)} '
+ 'is not a String');
+ }
+ }
+
_Link.fromPath(Path inputPath) : path = inputPath.toNativePath();
diff --git a/sdk/lib/io/secure_socket.dart b/sdk/lib/io/secure_socket.dart
index 1867050..2fd9659 100644
--- a/sdk/lib/io/secure_socket.dart
+++ b/sdk/lib/io/secure_socket.dart
@@ -96,6 +96,7 @@
return completer.future;
}
+
/**
* Takes an already connected [socket] and starts server side TLS
* handshake to make the communication secure. When the returned
@@ -205,6 +206,40 @@
external static void initialize({String database,
String password,
bool useBuiltinRoots: true});
+
+
+ /**
+ * Trust strings for use in [addCertificate].
+ */
+ static const String TRUST_ISSUE_SERVER_CERTIFICATES = 'C,,';
+ static const String TRUST_ISSUE_CLIENT_CERTIFICATES = 'T,,';
+ static const String TRUST_ISSUE_CLIENT_SERVER_CERTIFICATES = 'TC,,';
+ static const String TRUST_CERTIFICATE = 'P,,';
+
+
+ /**
+ * Adds a X509 certificate (for SSL and TLS secure networking) to the
+ * in-memory certificate database. Returns an X509Certificate object
+ * with information about the added certificate.
+ *
+ * [certificate] must be a list of bytes encoding a certificate in
+ * PEM format: a base64 encoded DER certificate, enclosed between
+ * "-----BEGIN CERTIFICATE-----" and "-----END CERTIFICATE-----".
+ *
+ * [trust] is a string specifying the allowed uses of this certificate.
+ * For example, 'TC,,' specifies that the certificate is for a certificate
+ * authority that is trusted to issue server and client certificates, so
+ * that a server or client certificate signed by this authority will be
+ * accepted.
+ *
+ * See the documentation of NSS certutil at
+ * http://developer.mozilla.org/en-US/docs/NSS_reference/NSS_tools_:_certutil
+ * or
+ * http://blogs.oracle.com/meena/entry/notes_about_trust_flags
+ * for more information about trust attributes.
+ */
+ external static X509Certificate addCertificate(List<int> certificate,
+ String trust);
}
@@ -412,7 +447,8 @@
static final int NUM_BUFFERS = 4;
// Is a buffer identifier for an encrypted buffer?
- static bool _isBufferEncrypted(int identifier) => identifier >= READ_ENCRYPTED;
+ static bool _isBufferEncrypted(int identifier) =>
+ identifier >= READ_ENCRYPTED;
RawSocket _socket;
final Completer<_RawSecureSocket> _handshakeComplete =
diff --git a/sdk/lib/io/websocket_impl.dart b/sdk/lib/io/websocket_impl.dart
index dd837445..140bd3b 100644
--- a/sdk/lib/io/websocket_impl.dart
+++ b/sdk/lib/io/websocket_impl.dart
@@ -572,6 +572,9 @@
StreamController _controller;
StreamSubscription _subscription;
bool _issuedPause = false;
+ // Only report error if the last message was a user-provided message and not a
+ // ping or pong message.
+ bool _reportError = false;
Completer _closeCompleter = new Completer();
Completer _completer;
@@ -613,8 +616,13 @@
_closeCompleter.complete(webSocket);
},
onError: (error) {
- if (!_done(error)) {
- _closeCompleter.completeError(error);
+ if (_reportError) {
+ if (!_done(error)) {
+ _closeCompleter.completeError(error);
+ }
+ } else {
+ _done();
+ _closeCompleter.complete(webSocket);
}
});
}
@@ -635,6 +643,7 @@
_completer = new Completer();
_subscription = stream.listen(
(data) {
+ _reportError = true;
_controller.add(data);
},
onDone: () {
@@ -662,6 +671,7 @@
void add(data) {
_ensureController();
+ _reportError = false;
_controller.add(data);
}
}
diff --git a/sdk/lib/mirrors/mirrors.dart b/sdk/lib/mirrors/mirrors.dart
index 5353755..f189dc0 100644
--- a/sdk/lib/mirrors/mirrors.dart
+++ b/sdk/lib/mirrors/mirrors.dart
@@ -1226,10 +1226,10 @@
* The list of strings passed to new [Symbol], and symbols that might be
* passed to [MirrorSystem.getName].
*
- * Combined with the names of [reflectiveTarget], [metaTargets] and their
- * members, this forms the complete list of strings passed to new [Symbol],
- * and symbols that might be passed to [MirrorSystem.getName] by the library
- * to which this metadata applies.
+ * Combined with the names of [targets], [metaTargets] and their members,
+ * this forms the complete list of strings passed to new [Symbol], and
+ * symbols that might be passed to [MirrorSystem.getName] by the library to
+ * which this metadata applies.
*
* The following text is non-normative:
*
diff --git a/sdk/lib/svg/dartium/svg_dartium.dart b/sdk/lib/svg/dartium/svg_dartium.dart
index 0e76bcc..35fa28a 100644
--- a/sdk/lib/svg/dartium/svg_dartium.dart
+++ b/sdk/lib/svg/dartium/svg_dartium.dart
@@ -3435,9 +3435,8 @@
Length operator[](int index) {
if (index < 0 || index >= length)
throw new RangeError.range(index, 0, length);
- return _nativeIndexedGetter(index);
+ return this.getItem(index)(index);
}
- Length _nativeIndexedGetter(int index) native "SVGLengthList_item_Callback";
void operator[]=(int index, Length value) {
throw new UnsupportedError("Cannot assign element of immutable List.");
@@ -4025,9 +4024,8 @@
Number operator[](int index) {
if (index < 0 || index >= length)
throw new RangeError.range(index, 0, length);
- return _nativeIndexedGetter(index);
+ return this.getItem(index)(index);
}
- Number _nativeIndexedGetter(int index) native "SVGNumberList_item_Callback";
void operator[]=(int index, Number value) {
throw new UnsupportedError("Cannot assign element of immutable List.");
@@ -5096,9 +5094,8 @@
PathSeg operator[](int index) {
if (index < 0 || index >= length)
throw new RangeError.range(index, 0, length);
- return _nativeIndexedGetter(index);
+ return this.getItem(index)(index);
}
- PathSeg _nativeIndexedGetter(int index) native "SVGPathSegList_item_Callback";
void operator[]=(int index, PathSeg value) {
throw new UnsupportedError("Cannot assign element of immutable List.");
@@ -6005,9 +6002,8 @@
String operator[](int index) {
if (index < 0 || index >= length)
throw new RangeError.range(index, 0, length);
- return _nativeIndexedGetter(index);
+ return this.getItem(index)(index);
}
- String _nativeIndexedGetter(int index) native "SVGStringList_item_Callback";
void operator[]=(int index, String value) {
throw new UnsupportedError("Cannot assign element of immutable List.");
@@ -7143,9 +7139,8 @@
Transform operator[](int index) {
if (index < 0 || index >= length)
throw new RangeError.range(index, 0, length);
- return _nativeIndexedGetter(index);
+ return this.getItem(index)(index);
}
- Transform _nativeIndexedGetter(int index) native "SVGTransformList_item_Callback";
void operator[]=(int index, Transform value) {
throw new UnsupportedError("Cannot assign element of immutable List.");
diff --git a/sdk/lib/typed_data/typed_data.dart b/sdk/lib/typed_data/typed_data.dart
index 739eae8..f75b4bb 100644
--- a/sdk/lib/typed_data/typed_data.dart
+++ b/sdk/lib/typed_data/typed_data.dart
@@ -798,6 +798,12 @@
external factory Float32x4List(int length);
/**
+ * Creates a [Float32x4List] with the same size as the [elements] list
+ * and copies over the elements.
+ */
+ external factory Float32x4List.fromList(List<Float32x4> elements);
+
+ /**
* Creates a [Float32x4List] _view_ of the specified region in the specified
* byte buffer. Changes in the [Float32x4List] will be visible in the byte
* buffer and vice versa. If the [offsetInBytes] index of the region is not
diff --git a/sdk/lib/web_gl/dart2js/web_gl_dart2js.dart b/sdk/lib/web_gl/dart2js/web_gl_dart2js.dart
index 11e9e01..65c742b 100644
--- a/sdk/lib/web_gl/dart2js/web_gl_dart2js.dart
+++ b/sdk/lib/web_gl/dart2js/web_gl_dart2js.dart
@@ -345,6 +345,39 @@
@DocsEditable()
+@DomName('ANGLEInstancedArrays')
+@Experimental() // untriaged
+class AngleInstancedArrays extends Interceptor native "ANGLEInstancedArrays" {
+
+ @DomName('ANGLEInstancedArrays.VERTEX_ATTRIB_ARRAY_DIVISOR_ANGLE')
+ @DocsEditable()
+ @Experimental() // untriaged
+ static const int VERTEX_ATTRIB_ARRAY_DIVISOR_ANGLE = 0x88FE;
+
+ @JSName('drawArraysInstancedANGLE')
+ @DomName('ANGLEInstancedArrays.drawArraysInstancedANGLE')
+ @DocsEditable()
+ @Experimental() // untriaged
+ void drawArraysInstancedAngle(int mode, int first, int count, int primcount) native;
+
+ @JSName('drawElementsInstancedANGLE')
+ @DomName('ANGLEInstancedArrays.drawElementsInstancedANGLE')
+ @DocsEditable()
+ @Experimental() // untriaged
+ void drawElementsInstancedAngle(int mode, int count, int type, int offset, int primcount) native;
+
+ @JSName('vertexAttribDivisorANGLE')
+ @DomName('ANGLEInstancedArrays.vertexAttribDivisorANGLE')
+ @DocsEditable()
+ @Experimental() // untriaged
+ void vertexAttribDivisorAngle(int index, int divisor) native;
+}
+// Copyright (c) 2012, 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.
+
+
+@DocsEditable()
@DomName('WebGLBuffer')
@Unstable()
class Buffer extends Interceptor native "WebGLBuffer" {
@@ -726,7 +759,7 @@
@DomName('WebGLLoseContext')
// http://www.khronos.org/registry/webgl/extensions/WEBGL_lose_context/
@Experimental()
-class LoseContext extends Interceptor native "WebGLLoseContext" {
+class LoseContext extends Interceptor native "WebGLLoseContext,WebGLExtensionLoseContext" {
@DomName('WebGLLoseContext.loseContext')
@DocsEditable()
diff --git a/sdk/lib/web_gl/dartium/web_gl_dartium.dart b/sdk/lib/web_gl/dartium/web_gl_dartium.dart
index 7637a680..411dd69 100644
--- a/sdk/lib/web_gl/dartium/web_gl_dartium.dart
+++ b/sdk/lib/web_gl/dartium/web_gl_dartium.dart
@@ -348,6 +348,39 @@
@DocsEditable()
+@DomName('ANGLEInstancedArrays')
+@Experimental() // untriaged
+class AngleInstancedArrays extends NativeFieldWrapperClass1 {
+
+ @DomName('ANGLEInstancedArrays.VERTEX_ATTRIB_ARRAY_DIVISOR_ANGLE')
+ @DocsEditable()
+ @Experimental() // untriaged
+ static const int VERTEX_ATTRIB_ARRAY_DIVISOR_ANGLE = 0x88FE;
+
+ @DomName('ANGLEInstancedArrays.drawArraysInstancedANGLE')
+ @DocsEditable()
+ @Experimental() // untriaged
+ void drawArraysInstancedAngle(int mode, int first, int count, int primcount) native "ANGLEInstancedArrays_drawArraysInstancedANGLE_Callback";
+
+ @DomName('ANGLEInstancedArrays.drawElementsInstancedANGLE')
+ @DocsEditable()
+ @Experimental() // untriaged
+ void drawElementsInstancedAngle(int mode, int count, int type, int offset, int primcount) native "ANGLEInstancedArrays_drawElementsInstancedANGLE_Callback";
+
+ @DomName('ANGLEInstancedArrays.vertexAttribDivisorANGLE')
+ @DocsEditable()
+ @Experimental() // untriaged
+ void vertexAttribDivisorAngle(int index, int divisor) native "ANGLEInstancedArrays_vertexAttribDivisorANGLE_Callback";
+
+}
+// Copyright (c) 2012, 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.
+
+// WARNING: Do not edit - generated code.
+
+
+@DocsEditable()
@DomName('WebGLBuffer')
@Unstable()
class Buffer extends NativeFieldWrapperClass1 {
diff --git a/tests/co19/co19-dart2dart.status b/tests/co19/co19-dart2dart.status
index 7b828a5..687842a 100644
--- a/tests/co19/co19-dart2dart.status
+++ b/tests/co19/co19-dart2dart.status
@@ -402,6 +402,12 @@
LibTest/math/atan_A01_t01: Fail, OK # co19 issue 44
[ $compiler == dart2dart ]
+Language/03_Overview/2_Privacy_A01_t06: Fail # co19 issue 463
+Language/09_Generics/09_Generics_A05_t01: Fail # co19 issue 463
+Language/11_Expressions/31_Type_Test_A04_t01: Fail # co19 issue 463
+Language/11_Expressions/32_Type_Cast_A03_t01: Fail # co19 issue 463
+Language/11_Expressions/32_Type_Cast_A03_t02: Fail # co19 issue 463
+Language/14_Types/2_Dynamic_Type_System_A02_t01: Fail # co19 issue 463
Language/14_Types/4_Interface_Types_A11_t01: Pass, Crash # Issue 8857
Language/14_Types/4_Interface_Types_A11_t02: Pass, Crash # Issue 8857
@@ -574,3 +580,12 @@
Language/11_Expressions/33_Argument_Definition_Test_A02_t02: Fail, OK # co19 issue 436
Language/11_Expressions/33_Argument_Definition_Test_A03_t01: Fail, OK # co19 issue 436
Language/11_Expressions/33_Argument_Definition_Test_A03_t02: Fail, OK # co19 issue 436
+
+Language/13_Libraries_and_Scripts/1_Imports_A03_t02: Fail # 481
+Language/13_Libraries_and_Scripts/1_Imports_A03_t05: Fail # 481
+Language/13_Libraries_and_Scripts/1_Imports_A03_t22: Fail # 481
+Language/13_Libraries_and_Scripts/1_Imports_A03_t25: Fail # 481
+Language/13_Libraries_and_Scripts/1_Imports_A03_t42: Fail # 481
+Language/13_Libraries_and_Scripts/1_Imports_A03_t45: Fail # 481
+Language/13_Libraries_and_Scripts/1_Imports_A03_t62: Fail # 481
+Language/13_Libraries_and_Scripts/1_Imports_A03_t65: Fail # 481
diff --git a/tests/co19/co19-dart2js.status b/tests/co19/co19-dart2js.status
index e7c7f0d..f4d828f 100644
--- a/tests/co19/co19-dart2js.status
+++ b/tests/co19/co19-dart2js.status
@@ -558,6 +558,15 @@
Language/11_Expressions/11_Instance_Creation_A04_t03: Fail # co19 issue 466
Language/11_Expressions/11_Instance_Creation_A04_t04: Fail # co19 issue 466
+Language/13_Libraries_and_Scripts/1_Imports_A03_t02: Fail # 481
+Language/13_Libraries_and_Scripts/1_Imports_A03_t05: Fail # 481
+Language/13_Libraries_and_Scripts/1_Imports_A03_t22: Fail # 481
+Language/13_Libraries_and_Scripts/1_Imports_A03_t25: Fail # 481
+Language/13_Libraries_and_Scripts/1_Imports_A03_t42: Fail # 481
+Language/13_Libraries_and_Scripts/1_Imports_A03_t45: Fail # 481
+Language/13_Libraries_and_Scripts/1_Imports_A03_t62: Fail # 481
+Language/13_Libraries_and_Scripts/1_Imports_A03_t65: Fail # 481
+
[ $compiler == dart2js && $checked ]
Language/03_Overview/1_Scoping_A02_t30: Fail # co19 issue 463
@@ -567,6 +576,8 @@
Language/11_Expressions/32_Type_Cast_A05_t04: Fail # co19 issue 463
Language/14_Types/8_Parameterized_Types_A02_t01: Fail # co19 issue 463
+Language/13_Libraries_and_Scripts/1_Imports_A03_t31: Fail # 481
+
[ $compiler == dart2js && $unchecked ]
LibTest/core/List/setRange_A05_t01: Fail # setRange throws StateError if there aren't enough elements in the iterable. Issue 402
diff --git a/tests/co19/co19-runtime.status b/tests/co19/co19-runtime.status
index c26a8af..7311058 100644
--- a/tests/co19/co19-runtime.status
+++ b/tests/co19/co19-runtime.status
@@ -93,8 +93,6 @@
Language/07_Classes/6_Constructors/3_Constant_Constructors_A05_t01: Fail # co19 issue 426
Language/11_Expressions/05_Strings_A02_t46: Fail # Dart issue 4009
Language/11_Expressions/05_Strings_A02_t48: Fail # Dart issue 4009
-Language/11_Expressions/11_Instance_Creation/1_New_A02_t03: Fail # Dart issue 3309
-Language/11_Expressions/11_Instance_Creation/1_New_A02_t05: Fail # Dart issue 7247
Language/11_Expressions/11_Instance_Creation/1_New_A09_t09: Fail # Dart issue 1372
Language/11_Expressions/11_Instance_Creation/2_Const_A10_t01: Fail # Dart issue 5775
Language/11_Expressions/30_Identifier_Reference_A05_t02: Fail # Dart issue 2492
@@ -394,6 +392,43 @@
Language/07_Classes/1_Instance_Methods_A02_t02: Fail # Override rules have been relaxed. Issue
Language/07_Classes/1_Instance_Methods_A02_t05: Fail # Override rules have been relaxed. Issue
+Language/03_Overview/1_Scoping_A02_t28: Fail # Issue 463
+Language/03_Overview/2_Privacy_A01_t06: Fail # Issue 463
+Language/09_Generics/09_Generics_A05_t01: Fail # Issue 463
+Language/11_Expressions/11_Instance_Creation/1_New_A05_t01: Fail # Issue 463
+Language/11_Expressions/11_Instance_Creation/1_New_A05_t02: Fail # Issue 463
+Language/11_Expressions/11_Instance_Creation/1_New_A05_t03: Fail # Issue 463
+Language/11_Expressions/11_Instance_Creation/2_Const_A07_t01: Fail # Issue 463
+Language/11_Expressions/11_Instance_Creation/2_Const_A07_t02: Fail # Issue 463
+Language/11_Expressions/11_Instance_Creation/2_Const_A07_t03: Fail # Issue 463
+Language/11_Expressions/11_Instance_Creation_A03_t01: Fail # Issue 463
+Language/11_Expressions/11_Instance_Creation_A03_t02: Fail # Issue 463
+Language/11_Expressions/11_Instance_Creation_A04_t01: Fail # Issue 463
+Language/11_Expressions/11_Instance_Creation_A04_t02: Fail # Issue 463
+Language/11_Expressions/11_Instance_Creation_A04_t03: Fail # Issue 463
+Language/11_Expressions/11_Instance_Creation_A04_t04: Fail # Issue 463
+Language/11_Expressions/31_Type_Test_A04_t01: Fail # Issue 463
+Language/11_Expressions/31_Type_Test_A05_t01: Fail # Issue 463
+Language/11_Expressions/31_Type_Test_A05_t02: Fail # Issue 463
+Language/11_Expressions/31_Type_Test_A05_t03: Fail # Issue 463
+Language/11_Expressions/32_Type_Cast_A03_t01: Fail # Issue 463
+Language/11_Expressions/32_Type_Cast_A03_t02: Fail # Issue 463
+Language/11_Expressions/32_Type_Cast_A04_t01: Fail # Issue 463
+Language/11_Expressions/32_Type_Cast_A04_t02: Fail # Issue 463
+Language/13_Libraries_and_Scripts/1_Imports_A03_t02: Fail # Issue 463
+Language/13_Libraries_and_Scripts/1_Imports_A03_t05: Fail # Issue 463
+Language/13_Libraries_and_Scripts/1_Imports_A03_t08: Fail # Issue 463
+Language/13_Libraries_and_Scripts/1_Imports_A03_t22: Fail # Issue 463
+Language/13_Libraries_and_Scripts/1_Imports_A03_t25: Fail # Issue 463
+Language/13_Libraries_and_Scripts/1_Imports_A03_t28: Fail # Issue 463
+Language/13_Libraries_and_Scripts/1_Imports_A03_t42: Fail # Issue 463
+Language/13_Libraries_and_Scripts/1_Imports_A03_t45: Fail # Issue 463
+Language/13_Libraries_and_Scripts/1_Imports_A03_t48: Fail # Issue 463
+Language/13_Libraries_and_Scripts/1_Imports_A03_t62: Fail # Issue 463
+Language/13_Libraries_and_Scripts/1_Imports_A03_t65: Fail # Issue 463
+Language/13_Libraries_and_Scripts/1_Imports_A03_t68: Fail # Issue 463
+Language/14_Types/2_Dynamic_Type_System_A02_t01: Fail # Issue 463
+
# end [ $compiler == none && $runtime == vm ]
@@ -404,6 +439,15 @@
[ $compiler == none && $runtime == vm && $checked ]
+Language/03_Overview/1_Scoping_A02_t30: Fail # co19 issue 463
+Language/09_Generics/09_Generics_A05_t02: Fail # co19 issue 463
+Language/13_Libraries_and_Scripts/1_Imports_A03_t06: Fail # co19 issue 463, bound is mapped to dynamic, no error.
+Language/13_Libraries_and_Scripts/1_Imports_A03_t26: Fail # co19 issue 463, bound is mapped to dynamic, no error.
+Language/13_Libraries_and_Scripts/1_Imports_A03_t46: Fail # co19 issue 463, bound is mapped to dynamic, no error.
+Language/13_Libraries_and_Scripts/1_Imports_A03_t66: Fail # co19 issue 463, bound is mapped to dynamic, no error.
+Language/13_Libraries_and_Scripts/1_Imports_A03_t31: Fail # co19 issue 463
+Language/14_Types/8_Parameterized_Types_A02_t01: Fail # co19 issue 463
+
LibTest/core/AssertionError/line_A01_t02: Fail # co19 issue 479
LibTest/core/Set/intersection_A03_t01: Fail # co19 issue 480
LibTest/core/TypeError/line_A01_t01: Fail # co19 issue 479
@@ -416,36 +460,40 @@
Language/11_Expressions/14_Function_Invocation/4_Function_Expression_Invocation_A01_t02: Fail, OK # co19 issue 405
Language/11_Expressions/15_Method_Invocation/1_Ordinary_Invocation_A05_t02: Fail, OK # co19 issue 405
Language/11_Expressions/15_Method_Invocation/1_Ordinary_Invocation_A05_t03: Fail, OK # co19 issue 405
-Language/11_Expressions/15_Method_Invocation/1_Ordinary_Invocation_A05_t06: Fail, OK # co19 issue 405
-Language/11_Expressions/15_Method_Invocation/4_Super_Invocation_A04_t01: Fail, OK # co19 issue 405
-Language/11_Expressions/15_Method_Invocation/4_Super_Invocation_A04_t02: Fail, OK # co19 issue 405
-Language/11_Expressions/15_Method_Invocation/4_Super_Invocation_A04_t03: Fail, OK # co19 issue 405
-Language/11_Expressions/15_Method_Invocation/4_Super_Invocation_A04_t04: Fail, OK # co19 issue 405
Language/11_Expressions/17_Getter_Invocation_A02_t01: Fail, OK # co19 issue 405
-Language/11_Expressions/17_Getter_Invocation_A02_t02: Fail, OK # co19 issue 405
Language/11_Expressions/18_Assignment_A05_t02: Fail, OK # co19 issue 405
Language/11_Expressions/18_Assignment_A05_t04: Fail, OK # co19 issue 405
Language/11_Expressions/18_Assignment_A05_t05: Fail, OK # co19 issue 405
Language/11_Expressions/18_Assignment_A08_t04: Fail, OK # co19 issue 405
Language/11_Expressions/30_Identifier_Reference_A07_t01: Fail, OK # co19 issue 460
-Language/12_Statements/09_Switch_A05_t01: Fail # co19 issue 442
+# Passing for the wrong reasons:
+Language/11_Expressions/15_Method_Invocation/4_Super_Invocation_A04_t01: Pass # co19 issues 405 and 463
+Language/11_Expressions/15_Method_Invocation/4_Super_Invocation_A04_t02: Pass # co19 issues 405 and 463
+Language/11_Expressions/15_Method_Invocation/4_Super_Invocation_A04_t03: Pass # co19 issues 405 and 463
+Language/11_Expressions/15_Method_Invocation/4_Super_Invocation_A04_t04: Pass # co19 issues 405 and 463
+Language/11_Expressions/15_Method_Invocation/1_Ordinary_Invocation_A05_t06: Pass # co19 issues 405 and 463
+Language/11_Expressions/17_Getter_Invocation_A02_t02: Pass # co19 issues 405 and 463
+Language/11_Expressions/32_Type_Cast_A05_t01: Fail # co19 issue 463 and issue 5280
+Language/11_Expressions/32_Type_Cast_A05_t02: Pass # co19 issue 463 and issue 5280
+Language/11_Expressions/32_Type_Cast_A05_t04: Pass # co19 issue 463 and issue 5280
-Language/03_Overview/1_Scoping_A02_t30: Fail
+Language/12_Statements/09_Switch_A05_t01: Fail # co19 issue 442
LibTest/core/Set/intersection_A01_t01: Fail # issue 390
LibTest/core/Set/intersection_A01_t02: Fail # issue 390
LibTest/core/Set/intersection_A01_t03: Fail # issue 390
-LibTest/collection/Queue/Queue.from_A01_t01: Fail # Issue 400
-LibTest/collection/Queue/Queue.from_A01_t02: Fail # Issue 400
-LibTest/core/List/List.from_A01_t01: Fail # Issue 400
-LibTest/core/List/every_A01_t01: Fail # Issue 400
-LibTest/core/Match/str_A01_t01: Fail # Issue 400
+LibTest/collection/Queue/Queue.from_A01_t01: Pass # Issue 400 and 463
+LibTest/collection/Queue/Queue.from_A01_t02: Pass # Issue 400 and 463
+LibTest/core/List/List.from_A01_t01: Pass # Issue 400 and 463
+LibTest/core/List/every_A01_t01: Pass # Issue 400 and 463
+LibTest/core/Match/str_A01_t01: Pass # Issue 400 and 463
-LibTest/async/Completer/completeError_A03_t02: Fail # No AsyncError anymore. Issue 407
-LibTest/async/Completer/complete_A02_t02: Fail # No AsyncError anymore. Issue 407
-LibTest/async/Future/catchError_A01_t01: Fail # No AsyncError anymore. Issue 407
-LibTest/async/Future/catchError_A01_t02: Fail # No AsyncError anymore. Issue 407
+# Passing for the wrong reasons:
+LibTest/async/Completer/completeError_A03_t02: Pass # No AsyncError anymore. Issue 407 and 463
+LibTest/async/Completer/complete_A02_t02: Pass # No AsyncError anymore. Issue 407 and 463
+LibTest/async/Future/catchError_A01_t01: Pass # No AsyncError anymore. Issue 407 and 463
+LibTest/async/Future/catchError_A01_t02: Pass # No AsyncError anymore. Issue 407 and 463
#end [ $compiler == none && $runtime == vm && $checked ]
diff --git a/tests/compiler/dart2js/deprecated_features_test.dart b/tests/compiler/dart2js/deprecated_features_test.dart
index ab679c3..58d8f07 100644
--- a/tests/compiler/dart2js/deprecated_features_test.dart
+++ b/tests/compiler/dart2js/deprecated_features_test.dart
@@ -54,11 +54,10 @@
// "message" is the expected message as a [String]. This is a
// short-term solution and should eventually changed to include
// a symbolic reference to a MessageKind.
- "0<#library('test');>::${deprecatedMessage('# tags')}\n"
- "19<part 'part.dart';>::${deprecatedMessage('missing part-of tag')}\n"
+ "15<part 'part.dart';>::${deprecatedMessage('missing part-of tag')}\n"
"0<>:/part.dart:info: Note: This file has no part-of tag, but it is being"
" used as a part.\n"
- "57<()>::${deprecatedMessage('getter parameters')}\n",
+ "53<()>::${deprecatedMessage('getter parameters')}\n",
messages.toString());
}
@@ -70,7 +69,7 @@
const Map<String, String> TEST_SOURCE =
const <String, String>{ '': """
-#library('test');
+library test;
part 'part.dart';
diff --git a/tests/compiler/dart2js/memory_compiler.dart b/tests/compiler/dart2js/memory_compiler.dart
index 3bf07d2..a45e1ca 100644
--- a/tests/compiler/dart2js/memory_compiler.dart
+++ b/tests/compiler/dart2js/memory_compiler.dart
@@ -1,68 +1,68 @@
-// Copyright (c) 2013, 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 dart2js.test.memory_compiler;
-
-import 'package:expect/expect.dart';
-import 'memory_source_file_helper.dart';
-
-import '../../../sdk/lib/_internal/compiler/implementation/dart2jslib.dart'
- show NullSink;
-
-import '../../../sdk/lib/_internal/compiler/compiler.dart'
- show DiagnosticHandler;
-
-import 'dart:async';
-
-import '../../../sdk/lib/_internal/compiler/implementation/mirrors/mirrors.dart';
-import '../../../sdk/lib/_internal/compiler/implementation/mirrors/dart2js_mirror.dart';
-
-Compiler compilerFor(Map<String,String> memorySourceFiles,
- {DiagnosticHandler diagnosticHandler,
- List<String> options: const []}) {
- Uri script = currentDirectory.resolve(nativeToUriPath(Platform.script));
- Uri libraryRoot = script.resolve('../../../sdk/');
- Uri packageRoot = script.resolve('./packages/');
-
- MemorySourceFileProvider.MEMORY_SOURCE_FILES = memorySourceFiles;
- var provider = new MemorySourceFileProvider();
- if (diagnosticHandler == null) {
- diagnosticHandler = new FormattingDiagnosticHandler(provider);
- }
-
- EventSink<String> outputProvider(String name, String extension) {
- if (name != '') throw 'Attempt to output file "$name.$extension"';
- return new NullSink('$name.$extension');
- }
-
- Compiler compiler = new Compiler(provider.readStringFromUri,
- outputProvider,
- diagnosticHandler,
- libraryRoot,
- packageRoot,
- options);
- return compiler;
-}
-
-Future<MirrorSystem> mirrorSystemFor(Map<String,String> memorySourceFiles,
- {DiagnosticHandler diagnosticHandler,
- List<String> options: const []}) {
- Uri script = currentDirectory.resolve(nativeToUriPath(Platform.script));
- Uri libraryRoot = script.resolve('../../../sdk/');
- Uri packageRoot = script.resolve('./packages/');
-
- MemorySourceFileProvider.MEMORY_SOURCE_FILES = memorySourceFiles;
- var provider = new MemorySourceFileProvider();
- if (diagnosticHandler == null) {
- diagnosticHandler = new FormattingDiagnosticHandler(provider);
- }
-
- List<Uri> libraries = <Uri>[];
- memorySourceFiles.forEach((String path, _) {
- libraries.add(new Uri(scheme: 'memory', path: path));
- });
-
- return analyze(libraries, libraryRoot, packageRoot,
- provider, diagnosticHandler, options);
-}
+// Copyright (c) 2013, 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 dart2js.test.memory_compiler;
+
+import 'package:expect/expect.dart';
+import 'memory_source_file_helper.dart';
+
+import '../../../sdk/lib/_internal/compiler/implementation/dart2jslib.dart'
+ show NullSink;
+
+import '../../../sdk/lib/_internal/compiler/compiler.dart'
+ show DiagnosticHandler;
+
+import 'dart:async';
+
+import '../../../sdk/lib/_internal/compiler/implementation/mirrors/mirrors.dart';
+import '../../../sdk/lib/_internal/compiler/implementation/mirrors/dart2js_mirror.dart';
+
+Compiler compilerFor(Map<String,String> memorySourceFiles,
+ {DiagnosticHandler diagnosticHandler,
+ List<String> options: const []}) {
+ Uri script = currentDirectory.resolve(nativeToUriPath(Platform.script));
+ Uri libraryRoot = script.resolve('../../../sdk/');
+ Uri packageRoot = script.resolve('./packages/');
+
+ MemorySourceFileProvider.MEMORY_SOURCE_FILES = memorySourceFiles;
+ var provider = new MemorySourceFileProvider();
+ if (diagnosticHandler == null) {
+ diagnosticHandler = new FormattingDiagnosticHandler(provider);
+ }
+
+ EventSink<String> outputProvider(String name, String extension) {
+ if (name != '') throw 'Attempt to output file "$name.$extension"';
+ return new NullSink('$name.$extension');
+ }
+
+ Compiler compiler = new Compiler(provider.readStringFromUri,
+ outputProvider,
+ diagnosticHandler,
+ libraryRoot,
+ packageRoot,
+ options);
+ return compiler;
+}
+
+Future<MirrorSystem> mirrorSystemFor(Map<String,String> memorySourceFiles,
+ {DiagnosticHandler diagnosticHandler,
+ List<String> options: const []}) {
+ Uri script = currentDirectory.resolve(nativeToUriPath(Platform.script));
+ Uri libraryRoot = script.resolve('../../../sdk/');
+ Uri packageRoot = script.resolve('./packages/');
+
+ MemorySourceFileProvider.MEMORY_SOURCE_FILES = memorySourceFiles;
+ var provider = new MemorySourceFileProvider();
+ if (diagnosticHandler == null) {
+ diagnosticHandler = new FormattingDiagnosticHandler(provider);
+ }
+
+ List<Uri> libraries = <Uri>[];
+ memorySourceFiles.forEach((String path, _) {
+ libraries.add(new Uri(scheme: 'memory', path: path));
+ });
+
+ return analyze(libraries, libraryRoot, packageRoot,
+ provider, diagnosticHandler, options);
+}
diff --git a/tests/compiler/dart2js/mirrors_lookup_test.dart b/tests/compiler/dart2js/mirrors_lookup_test.dart
index 26dbae9..8cda12e 100644
--- a/tests/compiler/dart2js/mirrors_lookup_test.dart
+++ b/tests/compiler/dart2js/mirrors_lookup_test.dart
@@ -1,263 +1,261 @@
-// Copyright (c) 2013, 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 dart2js.test.memory_source_file_helper;
-
-import 'package:expect/expect.dart';
-import 'memory_compiler.dart';
-import '../../../sdk/lib/_internal/compiler/implementation/mirrors/mirrors.dart';
-import '../../../sdk/lib/_internal/compiler/implementation/mirrors/mirrors_util.dart';
-
-const Map MEMORY_SOURCE_FILES = const {
- 'main.dart': r"""
-
-library main;
-
-import 'dart:async' as async show Future;
-
-var variable;
-
-method(a, [b]) {}
-
-class Class<A> {
- var field;
- var variable;
- method(c, {d}) {}
-}
-
-class Subclass<B> extends Class<B> {
- var subfield;
-}
-""",
-};
-
-void main() {
- mirrorSystemFor(MEMORY_SOURCE_FILES).then(
- (MirrorSystem mirrors) => test(mirrors),
- onError: (e) => Expect.fail('$e'));
-}
-
-void test(MirrorSystem mirrors) {
- LibraryMirror dartCore = mirrors.libraries[Uri.parse('dart:core')];
- Expect.isNotNull(dartCore);
-
- LibraryMirror dartAsync = mirrors.libraries[Uri.parse('dart:async')];
- Expect.isNotNull(dartAsync);
-
- LibraryMirror library = mirrors.libraries[Uri.parse('memory:main.dart')];
- Expect.isNotNull(library);
-
- // Check top-level scope.
-
- DeclarationMirror String_ = library.lookupInScope('String');
- Expect.isTrue(String_ is ClassMirror);
- Expect.equals('String', String_.simpleName);
- Expect.equals(dartCore, String_.owner);
-
- Expect.isNull(library.lookupInScope('async'));
- Expect.isNull(library.lookupInScope('Future'));
- DeclarationMirror Future_ = library.lookupInScope('async.Future');
- Expect.isTrue(Future_ is ClassMirror);
- Expect.equals('Future', Future_.simpleName);
- Expect.equals(dartAsync, Future_.owner);
- // Timer is not in scope.
- Expect.isNull(library.lookupInScope('Timer'));
- // async.Timer is hidden.
- Expect.isNull(library.lookupInScope('async.Timer'));
-
- DeclarationMirror variable = library.lookupInScope('variable');
- Expect.isTrue(variable is VariableMirror);
- Expect.equals('variable', variable.simpleName);
- Expect.equals('main.variable', variable.qualifiedName);
- Expect.equals(library, variable.owner);
- // Parameter `a` is not in scope.
- Expect.isNull(library.lookupInScope('a'));
- // Parameter `b` is not in scope.
- Expect.isNull(library.lookupInScope('b'));
-
- DeclarationMirror method = library.lookupInScope('method');
- Expect.isTrue(method is MethodMirror);
- Expect.equals('method', method.simpleName);
- Expect.equals('main.method', method.qualifiedName);
- Expect.equals(library, method.owner);
-
- DeclarationMirror Class = library.lookupInScope('Class');
- Expect.isTrue(Class is ClassMirror);
- Expect.equals('Class', Class.simpleName);
- Expect.equals('main.Class', Class.qualifiedName);
- Expect.equals(library, Class.owner);
- // Type variable `A` is not in scope.
- Expect.isNull(library.lookupInScope('A'));
-
- DeclarationMirror Subclass = library.lookupInScope('Subclass');
- Expect.isTrue(Subclass is ClassMirror);
- Expect.equals('Subclass', Subclass.simpleName);
- Expect.equals('main.Subclass', Subclass.qualifiedName);
- Expect.equals(library, Subclass.owner);
- // Type variable `B` is not in scope.
- Expect.isNull(library.lookupInScope('B'));
-
- // Check top-level declaration scope.
- checkTopScope(DeclarationMirror declaration) {
- Expect.equals(String_, declaration.lookupInScope('String'));
- Expect.equals(Future_, declaration.lookupInScope('async.Future'));
- Expect.isNull(method.lookupInScope('Timer'));
- Expect.isNull(declaration.lookupInScope('async.Timer'));
- Expect.equals(variable, declaration.lookupInScope('variable'));
- Expect.equals(method, declaration.lookupInScope('method'));
- Expect.equals(Class, declaration.lookupInScope('Class'));
- // Type variable `A` is not in scope.
- Expect.isNull(declaration.lookupInScope('A'));
- // Field `field` is not in scope.
- Expect.isNull(declaration.lookupInScope('field'));
- Expect.equals(Subclass, declaration.lookupInScope('Subclass'));
- // Type variable `B` is not in scope.
- Expect.isNull(declaration.lookupInScope('B'));
- // Field `subfield` is not in scope.
- Expect.isNull(declaration.lookupInScope('subfield'));
- }
-
- checkTopScope(variable);
- // Parameter `a` is not in scope of `variable`.
- Expect.isNull(variable.lookupInScope('a'));
- // Parameter `b` is not in scope of `variable`.
- Expect.isNull(variable.lookupInScope('b'));
-
- checkTopScope(method);
- // Parameter `a` is in scope of `method`.
- Expect.isTrue(method.lookupInScope('a') is ParameterMirror);
- // Parameter `b` is in scope of `method`.
- Expect.isTrue(method.lookupInScope('b') is ParameterMirror);
-
- // Check class scope.
- DeclarationMirror Class_field = Class.lookupInScope('field');
- Expect.isTrue(Class_field is VariableMirror);
- Expect.notEquals(variable, Class_field);
- Expect.equals(Class, Class_field.owner);
-
- DeclarationMirror Class_variable = Class.lookupInScope('variable');
- Expect.isTrue(Class_variable is VariableMirror);
- Expect.notEquals(variable, Class_variable);
- Expect.equals(Class, Class_variable.owner);
-
- DeclarationMirror Class_method = Class.lookupInScope('method');
- Expect.isTrue(Class_method is MethodMirror);
- Expect.notEquals(method, Class_method);
- Expect.equals(Class, Class_method.owner);
-
- checkClassScope(DeclarationMirror declaration, {bool parametersInScope}) {
- Expect.equals(String_, declaration.lookupInScope('String'));
- Expect.equals(Future_, declaration.lookupInScope('async.Future'));
- Expect.isNull(declaration.lookupInScope('Timer'));
- Expect.isNull(declaration.lookupInScope('async.Timer'));
-
- Expect.equals(Class_field, declaration.lookupInScope('field'));
- Expect.equals(Class_variable, declaration.lookupInScope('variable'));
- Expect.equals(Class_method, declaration.lookupInScope('method'));
-
- // Parameter `a` is not in scope.
- Expect.isNull(declaration.lookupInScope('a'));
- // Parameter `b` is not in scope.
- Expect.isNull(declaration.lookupInScope('b'));
-
- if (parametersInScope) {
- // Parameter `c` is in scope.
- Expect.isTrue(declaration.lookupInScope('c') is ParameterMirror);
- // Parameter `d` is in scope.
- Expect.isTrue(declaration.lookupInScope('d') is ParameterMirror);
- } else {
- // Parameter `c` is not in scope.
- Expect.isNull(declaration.lookupInScope('c'));
- // Parameter `d` is not in scope.
- Expect.isNull(declaration.lookupInScope('d'));
- }
-
- Expect.equals(Class, declaration.lookupInScope('Class'));
- // Type variable `A` is in scope.
- Expect.isTrue(declaration.lookupInScope('A') is TypeVariableMirror);
- Expect.equals(Subclass, declaration.lookupInScope('Subclass'));
- // Type variable `B` is not in scope.
- Expect.isNull(declaration.lookupInScope('B'));
- // Field `subfield` is not in scope.
- Expect.isNull(declaration.lookupInScope('subfield'));
- }
- checkClassScope(Class, parametersInScope: false);
- checkClassScope(Class_field, parametersInScope: false);
- checkClassScope(Class_variable, parametersInScope: false);
- checkClassScope(Class_method, parametersInScope: true);
-
- // Check class scope.
- DeclarationMirror Subclass_subfield = Subclass.lookupInScope('subfield');
- Expect.isTrue(Subclass_subfield is VariableMirror);
- Expect.notEquals(variable, Subclass_subfield);
- Expect.equals(Subclass, Subclass_subfield.owner);
-
- checkSubclassScope(DeclarationMirror declaration) {
- Expect.equals(String_, declaration.lookupInScope('String'));
- Expect.equals(Future_, declaration.lookupInScope('async.Future'));
- Expect.isNull(declaration.lookupInScope('Timer'));
- Expect.isNull(declaration.lookupInScope('async.Timer'));
-
- // Top level `variable` is in scope.
- Expect.equals(variable, declaration.lookupInScope('variable'));
- // Top level `method` is in scope.
- Expect.equals(method, declaration.lookupInScope('method'));
-
- // Parameter `a` is not in scope
- Expect.isNull(declaration.lookupInScope('a'));
- // Parameter `b` is not in scope
- Expect.isNull(declaration.lookupInScope('b'));
-
- // Parameter `c` is not in scope.
- Expect.isNull(declaration.lookupInScope('c'));
- // Parameter `d` is not in scope.
- Expect.isNull(declaration.lookupInScope('d'));
-
- Expect.equals(Class, declaration.lookupInScope('Class'));
- // Type variable `A` is not in scope
- Expect.isNull(declaration.lookupInScope('A'));
- // Field `field` is in scope
- Expect.equals(Class_field, declaration.lookupInScope('field'));
- Expect.equals(Subclass, declaration.lookupInScope('Subclass'));
- // Type variable `B` is in scope
- Expect.isTrue(declaration.lookupInScope('B') is TypeVariableMirror);
- // Field `subfield` is in scope
- Expect.equals(Subclass_subfield, declaration.lookupInScope('subfield'));
- }
- checkSubclassScope(Subclass);
- checkSubclassScope(Subclass_subfield);
-
- // `Timer` is in scope of `Future`.
- Expect.isTrue(Future_.lookupInScope('Timer') is ClassMirror);
-
- // Check qualified lookup.
- Expect.equals(variable, lookupQualifiedInScope(library, 'variable'));
- Expect.equals(method, lookupQualifiedInScope(library, 'method'));
- Expect.isTrue(lookupQualifiedInScope(library, 'method.a') is ParameterMirror);
-
- Expect.equals(Class, lookupQualifiedInScope(library, 'Class'));
- Expect.isTrue(
- lookupQualifiedInScope(library, 'Class.A') is TypeVariableMirror);
-
- Expect.isNull(library.lookupInScope('Class.field'));
- Expect.equals(Class_field, lookupQualifiedInScope(library, 'Class.field'));
-
- Expect.equals(Class_method, lookupQualifiedInScope(library, 'Class.method'));
- Expect.isTrue(
- lookupQualifiedInScope(library, 'Class.method.c') is ParameterMirror);
-
- // `field` should not be found through the prefix `Subclass`.
- Expect.isNull(lookupQualifiedInScope(library, 'Subclass.field'));
- Expect.equals(Subclass_subfield,
- lookupQualifiedInScope(library, 'Subclass.subfield'));
-
- Expect.equals(Future_, lookupQualifiedInScope(library, 'async.Future'));
- Expect.isTrue(
- lookupQualifiedInScope(library, 'async.Future.then') is MethodMirror);
- // `Timer` should not be found through the prefix `async.Future`.
- Expect.isNull(
- lookupQualifiedInScope(library, 'async.Future.Timer'));
-}
-
-
+// Copyright (c) 2013, 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 dart2js.test.memory_source_file_helper;
+
+import 'package:expect/expect.dart';
+import 'memory_compiler.dart';
+import '../../../sdk/lib/_internal/compiler/implementation/mirrors/mirrors.dart';
+import '../../../sdk/lib/_internal/compiler/implementation/mirrors/mirrors_util.dart';
+
+const Map MEMORY_SOURCE_FILES = const {
+ 'main.dart': r"""
+
+library main;
+
+import 'dart:async' as async show Future;
+
+var variable;
+
+method(a, [b]) {}
+
+class Class<A> {
+ var field;
+ var variable;
+ method(c, {d}) {}
+}
+
+class Subclass<B> extends Class<B> {
+ var subfield;
+}
+""",
+};
+
+void main() {
+ mirrorSystemFor(MEMORY_SOURCE_FILES).then(
+ (MirrorSystem mirrors) => test(mirrors),
+ onError: (e) => Expect.fail('$e'));
+}
+
+void test(MirrorSystem mirrors) {
+ LibraryMirror dartCore = mirrors.libraries[Uri.parse('dart:core')];
+ Expect.isNotNull(dartCore);
+
+ LibraryMirror dartAsync = mirrors.libraries[Uri.parse('dart:async')];
+ Expect.isNotNull(dartAsync);
+
+ LibraryMirror library = mirrors.libraries[Uri.parse('memory:main.dart')];
+ Expect.isNotNull(library);
+
+ // Check top-level scope.
+
+ DeclarationMirror String_ = library.lookupInScope('String');
+ Expect.isTrue(String_ is ClassMirror);
+ Expect.equals('String', String_.simpleName);
+ Expect.equals(dartCore, String_.owner);
+
+ Expect.isNull(library.lookupInScope('async'));
+ Expect.isNull(library.lookupInScope('Future'));
+ DeclarationMirror Future_ = library.lookupInScope('async.Future');
+ Expect.isTrue(Future_ is ClassMirror);
+ Expect.equals('Future', Future_.simpleName);
+ Expect.equals(dartAsync, Future_.owner);
+ // Timer is not in scope.
+ Expect.isNull(library.lookupInScope('Timer'));
+ // async.Timer is hidden.
+ Expect.isNull(library.lookupInScope('async.Timer'));
+
+ DeclarationMirror variable = library.lookupInScope('variable');
+ Expect.isTrue(variable is VariableMirror);
+ Expect.equals('variable', variable.simpleName);
+ Expect.equals('main.variable', variable.qualifiedName);
+ Expect.equals(library, variable.owner);
+ // Parameter `a` is not in scope.
+ Expect.isNull(library.lookupInScope('a'));
+ // Parameter `b` is not in scope.
+ Expect.isNull(library.lookupInScope('b'));
+
+ DeclarationMirror method = library.lookupInScope('method');
+ Expect.isTrue(method is MethodMirror);
+ Expect.equals('method', method.simpleName);
+ Expect.equals('main.method', method.qualifiedName);
+ Expect.equals(library, method.owner);
+
+ DeclarationMirror Class = library.lookupInScope('Class');
+ Expect.isTrue(Class is ClassMirror);
+ Expect.equals('Class', Class.simpleName);
+ Expect.equals('main.Class', Class.qualifiedName);
+ Expect.equals(library, Class.owner);
+ // Type variable `A` is not in scope.
+ Expect.isNull(library.lookupInScope('A'));
+
+ DeclarationMirror Subclass = library.lookupInScope('Subclass');
+ Expect.isTrue(Subclass is ClassMirror);
+ Expect.equals('Subclass', Subclass.simpleName);
+ Expect.equals('main.Subclass', Subclass.qualifiedName);
+ Expect.equals(library, Subclass.owner);
+ // Type variable `B` is not in scope.
+ Expect.isNull(library.lookupInScope('B'));
+
+ // Check top-level declaration scope.
+ checkTopScope(DeclarationMirror declaration) {
+ Expect.equals(String_, declaration.lookupInScope('String'));
+ Expect.equals(Future_, declaration.lookupInScope('async.Future'));
+ Expect.isNull(method.lookupInScope('Timer'));
+ Expect.isNull(declaration.lookupInScope('async.Timer'));
+ Expect.equals(variable, declaration.lookupInScope('variable'));
+ Expect.equals(method, declaration.lookupInScope('method'));
+ Expect.equals(Class, declaration.lookupInScope('Class'));
+ // Type variable `A` is not in scope.
+ Expect.isNull(declaration.lookupInScope('A'));
+ // Field `field` is not in scope.
+ Expect.isNull(declaration.lookupInScope('field'));
+ Expect.equals(Subclass, declaration.lookupInScope('Subclass'));
+ // Type variable `B` is not in scope.
+ Expect.isNull(declaration.lookupInScope('B'));
+ // Field `subfield` is not in scope.
+ Expect.isNull(declaration.lookupInScope('subfield'));
+ }
+
+ checkTopScope(variable);
+ // Parameter `a` is not in scope of `variable`.
+ Expect.isNull(variable.lookupInScope('a'));
+ // Parameter `b` is not in scope of `variable`.
+ Expect.isNull(variable.lookupInScope('b'));
+
+ checkTopScope(method);
+ // Parameter `a` is in scope of `method`.
+ Expect.isTrue(method.lookupInScope('a') is ParameterMirror);
+ // Parameter `b` is in scope of `method`.
+ Expect.isTrue(method.lookupInScope('b') is ParameterMirror);
+
+ // Check class scope.
+ DeclarationMirror Class_field = Class.lookupInScope('field');
+ Expect.isTrue(Class_field is VariableMirror);
+ Expect.notEquals(variable, Class_field);
+ Expect.equals(Class, Class_field.owner);
+
+ DeclarationMirror Class_variable = Class.lookupInScope('variable');
+ Expect.isTrue(Class_variable is VariableMirror);
+ Expect.notEquals(variable, Class_variable);
+ Expect.equals(Class, Class_variable.owner);
+
+ DeclarationMirror Class_method = Class.lookupInScope('method');
+ Expect.isTrue(Class_method is MethodMirror);
+ Expect.notEquals(method, Class_method);
+ Expect.equals(Class, Class_method.owner);
+
+ checkClassScope(DeclarationMirror declaration, {bool parametersInScope}) {
+ Expect.equals(String_, declaration.lookupInScope('String'));
+ Expect.equals(Future_, declaration.lookupInScope('async.Future'));
+ Expect.isNull(declaration.lookupInScope('Timer'));
+ Expect.isNull(declaration.lookupInScope('async.Timer'));
+
+ Expect.equals(Class_field, declaration.lookupInScope('field'));
+ Expect.equals(Class_variable, declaration.lookupInScope('variable'));
+ Expect.equals(Class_method, declaration.lookupInScope('method'));
+
+ // Parameter `a` is not in scope.
+ Expect.isNull(declaration.lookupInScope('a'));
+ // Parameter `b` is not in scope.
+ Expect.isNull(declaration.lookupInScope('b'));
+
+ if (parametersInScope) {
+ // Parameter `c` is in scope.
+ Expect.isTrue(declaration.lookupInScope('c') is ParameterMirror);
+ // Parameter `d` is in scope.
+ Expect.isTrue(declaration.lookupInScope('d') is ParameterMirror);
+ } else {
+ // Parameter `c` is not in scope.
+ Expect.isNull(declaration.lookupInScope('c'));
+ // Parameter `d` is not in scope.
+ Expect.isNull(declaration.lookupInScope('d'));
+ }
+
+ Expect.equals(Class, declaration.lookupInScope('Class'));
+ // Type variable `A` is in scope.
+ Expect.isTrue(declaration.lookupInScope('A') is TypeVariableMirror);
+ Expect.equals(Subclass, declaration.lookupInScope('Subclass'));
+ // Type variable `B` is not in scope.
+ Expect.isNull(declaration.lookupInScope('B'));
+ // Field `subfield` is not in scope.
+ Expect.isNull(declaration.lookupInScope('subfield'));
+ }
+ checkClassScope(Class, parametersInScope: false);
+ checkClassScope(Class_field, parametersInScope: false);
+ checkClassScope(Class_variable, parametersInScope: false);
+ checkClassScope(Class_method, parametersInScope: true);
+
+ // Check class scope.
+ DeclarationMirror Subclass_subfield = Subclass.lookupInScope('subfield');
+ Expect.isTrue(Subclass_subfield is VariableMirror);
+ Expect.notEquals(variable, Subclass_subfield);
+ Expect.equals(Subclass, Subclass_subfield.owner);
+
+ checkSubclassScope(DeclarationMirror declaration) {
+ Expect.equals(String_, declaration.lookupInScope('String'));
+ Expect.equals(Future_, declaration.lookupInScope('async.Future'));
+ Expect.isNull(declaration.lookupInScope('Timer'));
+ Expect.isNull(declaration.lookupInScope('async.Timer'));
+
+ // Top level `variable` is in scope.
+ Expect.equals(variable, declaration.lookupInScope('variable'));
+ // Top level `method` is in scope.
+ Expect.equals(method, declaration.lookupInScope('method'));
+
+ // Parameter `a` is not in scope
+ Expect.isNull(declaration.lookupInScope('a'));
+ // Parameter `b` is not in scope
+ Expect.isNull(declaration.lookupInScope('b'));
+
+ // Parameter `c` is not in scope.
+ Expect.isNull(declaration.lookupInScope('c'));
+ // Parameter `d` is not in scope.
+ Expect.isNull(declaration.lookupInScope('d'));
+
+ Expect.equals(Class, declaration.lookupInScope('Class'));
+ // Type variable `A` is not in scope
+ Expect.isNull(declaration.lookupInScope('A'));
+ // Field `field` is in scope
+ Expect.equals(Class_field, declaration.lookupInScope('field'));
+ Expect.equals(Subclass, declaration.lookupInScope('Subclass'));
+ // Type variable `B` is in scope
+ Expect.isTrue(declaration.lookupInScope('B') is TypeVariableMirror);
+ // Field `subfield` is in scope
+ Expect.equals(Subclass_subfield, declaration.lookupInScope('subfield'));
+ }
+ checkSubclassScope(Subclass);
+ checkSubclassScope(Subclass_subfield);
+
+ // `Timer` is in scope of `Future`.
+ Expect.isTrue(Future_.lookupInScope('Timer') is ClassMirror);
+
+ // Check qualified lookup.
+ Expect.equals(variable, lookupQualifiedInScope(library, 'variable'));
+ Expect.equals(method, lookupQualifiedInScope(library, 'method'));
+ Expect.isTrue(lookupQualifiedInScope(library, 'method.a') is ParameterMirror);
+
+ Expect.equals(Class, lookupQualifiedInScope(library, 'Class'));
+ Expect.isTrue(
+ lookupQualifiedInScope(library, 'Class.A') is TypeVariableMirror);
+
+ Expect.isNull(library.lookupInScope('Class.field'));
+ Expect.equals(Class_field, lookupQualifiedInScope(library, 'Class.field'));
+
+ Expect.equals(Class_method, lookupQualifiedInScope(library, 'Class.method'));
+ Expect.isTrue(
+ lookupQualifiedInScope(library, 'Class.method.c') is ParameterMirror);
+
+ // `field` should not be found through the prefix `Subclass`.
+ Expect.isNull(lookupQualifiedInScope(library, 'Subclass.field'));
+ Expect.equals(Subclass_subfield,
+ lookupQualifiedInScope(library, 'Subclass.subfield'));
+
+ Expect.equals(Future_, lookupQualifiedInScope(library, 'async.Future'));
+ Expect.isTrue(
+ lookupQualifiedInScope(library, 'async.Future.then') is MethodMirror);
+ // `Timer` should not be found through the prefix `async.Future`.
+ Expect.isNull(
+ lookupQualifiedInScope(library, 'async.Future.Timer'));
+}
diff --git a/tests/compiler/dart2js/mirrors_used_test.dart b/tests/compiler/dart2js/mirrors_used_test.dart
new file mode 100644
index 0000000..09fdd29
--- /dev/null
+++ b/tests/compiler/dart2js/mirrors_used_test.dart
@@ -0,0 +1,95 @@
+// Copyright (c) 2013, 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 @MirrorsUsed annotation suppress hints and that only
+/// requested elements are retained for reflection.
+library dart2js.test.mirrors_used_test;
+
+import 'package:expect/expect.dart';
+
+import 'memory_compiler.dart' show
+ compilerFor;
+
+import '../../../sdk/lib/_internal/compiler/implementation/apiimpl.dart' show
+ Compiler;
+
+import '../../../sdk/lib/_internal/compiler/implementation/dart2jslib.dart' show
+ SourceString;
+
+import
+ '../../../sdk/lib/_internal/compiler/implementation/elements/elements.dart'
+show
+ Elements;
+
+void expectOnlyVerboseInfo(Uri uri, int begin, int end, String message, kind) {
+ if (kind.name == 'verbose info') {
+ print(message);
+ return;
+ }
+ throw '$uri:$begin:$end: $kind: $message';
+}
+
+void main() {
+ Compiler compiler = compilerFor(
+ MEMORY_SOURCE_FILES, diagnosticHandler: expectOnlyVerboseInfo);
+ compiler.runCompiler(Uri.parse('memory:main.dart'));
+
+ print('');
+ List generatedCode =
+ Elements.sortedByPosition(compiler.enqueuer.codegen.generatedCode.keys);
+ for (var element in generatedCode) {
+ print(element);
+ }
+ print('');
+
+ // This assertion can fail for two reasons:
+ // 1. Too many elements retained for reflection.
+ // 2. Some code was refactored, and there are more methods.
+ // Either situation could be problematic, but in situation 2, it is often
+ // acceptable to increase [expectedMethodCount] a little.
+ int expectedMethodCount = 315;
+ Expect.isTrue(
+ generatedCode.length <= expectedMethodCount,
+ 'Too many compiled methods: '
+ '${generatedCode.length} > $expectedMethodCount');
+
+ for (var library in compiler.libraries.values) {
+ library.forEachLocalMember((member) {
+ if (library == compiler.mainApp) {
+ // TODO(ahe): We currently retain the entire library. Update this test
+ // to test that only Foo is retained.
+ Expect.isTrue(
+ compiler.backend.isNeededForReflection(member), '$member');
+ } else {
+ Expect.isFalse(
+ compiler.backend.isNeededForReflection(member), '$member');
+ }
+ });
+ }
+}
+
+const MEMORY_SOURCE_FILES = const <String, String> {
+ 'main.dart': """
+@MirrorsUsed(targets: const [Foo], override: '*')
+import 'dart:mirrors';
+
+import 'library.dart';
+
+class Foo {}
+
+main() {
+ useReflect(Foo);
+}
+""",
+ 'library.dart': """
+library lib;
+
+import 'dart:mirrors';
+
+useReflect(type) {
+ print(new Symbol('Foo'));
+ print(MirrorSystem.getName(reflectClass(type).owner.qualifiedName));
+}
+""",
+};
diff --git a/tests/html/cssstyledeclaration_test.dart b/tests/html/cssstyledeclaration_test.dart
index 13a9730..45df00c 100644
--- a/tests/html/cssstyledeclaration_test.dart
+++ b/tests/html/cssstyledeclaration_test.dart
@@ -97,4 +97,52 @@
// Should not throw an error.
element.style.background = 'some_bad_value';
});
+
+ test('css multi get', () {
+ var listElement = new Element.html('<ul class="foo">'
+ '<li class="bar" style="background-color: red; border-left: 10px;">'
+ '<li class="baz" style="background-color: black;>'
+ '<li class="baz classy" style="background-color: blue; ">'
+ '</ul>');
+ document.documentElement.children.add(listElement);
+
+ var elements = document.queryAll('li');
+ expect(elements.style.backgroundColor, equals('red'));
+ expect(elements.style.borderLeftWidth, equals('10px'));
+ elements = document.queryAll('.baz');
+ expect(elements.style.backgroundColor, equals('black'));
+ expect(elements.style.borderLeftWidth, equals(''));
+ elements = document.queryAll('.bar');
+ expect(elements.style.backgroundColor, equals('red'));
+ });
+
+ test('css multi set', () {
+ var listElement = new Element.html('<ul class="foo">'
+ '<li class="bar" style="background-color: red; border-left: 10px;">'
+ '<li class="baz" style="background-color: black;>'
+ '<li class="baz" id="wat" style="background-color: blue; ">'
+ '</ul>');
+ document.documentElement.children.add(listElement);
+
+ var elements = document.queryAll('li');
+ elements.style.backgroundColor = 'green';
+ expect(elements.style.backgroundColor, equals('green'));
+ expect(elements.style.borderLeftWidth, equals('10px'));
+
+ elements = document.queryAll('.baz');
+ expect(elements.style.backgroundColor, equals('green'));
+ elements.style.backgroundColor = 'yellow';
+ expect(elements.style.backgroundColor, equals('yellow'));
+ expect(elements.style.borderLeftWidth, equals(''));
+
+ elements = document.queryAll('.bar');
+ expect(elements.style.backgroundColor, equals('green'));
+ elements = document.queryAll('#wat');
+ expect(elements.style.backgroundColor, equals('yellow'));
+
+ elements.style.borderLeftWidth = '18px';
+ expect(elements.style.borderLeftWidth, equals('18px'));
+ elements = document.queryAll('li');
+ expect(elements.style.borderLeftWidth, equals('10px'));
+ });
}
diff --git a/tests/html/custom_elements_test.dart b/tests/html/custom_elements_test.dart
index 7e17912..71714b3 100644
--- a/tests/html/custom_elements_test.dart
+++ b/tests/html/custom_elements_test.dart
@@ -2,9 +2,9 @@
// 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 blob_test;
+library custom_elements_test;
import '../../pkg/unittest/lib/unittest.dart';
-import '../../pkg/unittest/lib/html_config.dart';
+import '../../pkg/unittest/lib/html_individual_config.dart';
import 'dart:html';
class CustomType extends Element {
@@ -17,77 +17,82 @@
class NotAnElement {}
main() {
- useHtmlConfiguration();
+ useHtmlIndividualConfiguration();
- test('register', () {
- document.register('x-type1', CustomType);
+ group('register', () {
+ test('register', () {
+ document.register('x-type1', CustomType);
- var element = new Element.tag('x-type1');
- expect(element, isNotNull);
- expect(element is CustomType, isTrue);
- expect(element.onCreatedCalled, isTrue);
- });
+ var element = new Element.tag('x-type1');
+ expect(element, isNotNull);
+ expect(element is CustomType, isTrue);
+ expect(element.onCreatedCalled, isTrue);
+ });
- test('register twice', () {
- document.register('x-type2', CustomType);
- expect(() {
+ test('register twice', () {
document.register('x-type2', CustomType);
- }, throws, reason: 'Cannot register a tag more than once.');
+ expect(() {
+ document.register('x-type2', CustomType);
+ }, throws, reason: 'Cannot register a tag more than once.');
- document.register('x-type3', CustomType);
+ document.register('x-type3', CustomType);
- var element = new Element.tag('x-type3');
- expect(element, isNotNull);
- expect(element is CustomType, isTrue);
- });
-
- test('register null', () {
- expect(() {
- document.register('x-type4', null);
- }, throws, reason: 'Cannot register a null type.');
- });
-
- test('register native', () {
- expect(() {
- document.register('x-type5', BodyElement);
- }, throws, reason: 'Cannot register a native element.');
- });
-
- test('register non-element', () {
- expect(() {
- document.register('x-type6', NotAnElement);
- }, throws, reason: 'Cannot register a non-element.');
- });
-
- test('pre-registration construction', () {
- var dom = new Element.html('<div><x-type7></x-type7></div>');
- var preElement = dom.children[0];
- expect(preElement, isNotNull);
- expect(preElement is UnknownElement, isTrue);
- var firedOnPre = false;
- preElement.onFocus.listen((_) {
- firedOnPre = true;
+ var element = new Element.tag('x-type3');
+ expect(element, isNotNull);
+ expect(element is CustomType, isTrue);
});
- document.register('x-type7', CustomType);
-
- var postElement = dom.children[0];
- expect(postElement, isNotNull);
- expect(postElement is CustomType, isTrue);
- expect(postElement.onCreatedCalled, isTrue);
-
- // Element from first query remains an UnknownElement.
- expect(preElement is UnknownElement, isTrue);
- expect(preElement.parent, isNull);
- expect(dom.children.length, 1);
-
- var firedOnPost = false;
- postElement.onFocus.listen((_) {
- firedOnPost = true;
+ test('register null', () {
+ expect(() {
+ document.register('x-type4', null);
+ }, throws, reason: 'Cannot register a null type.');
});
- // Event handlers should not persist to new element.
- postElement.dispatchEvent(new Event('focus'));
- expect(firedOnPre, isFalse);
- expect(firedOnPost, isTrue);
+
+ test('register native', () {
+ expect(() {
+ document.register('x-type5', BodyElement);
+ }, throws, reason: 'Cannot register a native element.');
+ });
+
+ test('register non-element', () {
+ expect(() {
+ document.register('x-type6', NotAnElement);
+ }, throws, reason: 'Cannot register a non-element.');
+ });
+ });
+
+ group('preregister', () {
+ // TODO(vsm): Modify this test once we agree on the proper semantics.
+ test('pre-registration construction', () {
+ var dom = new Element.html('<div><x-type7></x-type7></div>');
+ var preElement = dom.children[0];
+ expect(preElement, isNotNull);
+ expect(preElement is UnknownElement, isTrue);
+ var firedOnPre = false;
+ preElement.onFocus.listen((_) {
+ firedOnPre = true;
+ });
+
+ document.register('x-type7', CustomType);
+
+ var postElement = dom.children[0];
+ expect(postElement, isNotNull);
+ expect(postElement is CustomType, isTrue);
+ expect(postElement.onCreatedCalled, isTrue);
+
+ // Element from first query remains an UnknownElement.
+ expect(preElement is UnknownElement, isTrue);
+ expect(preElement.parent, isNull);
+ expect(dom.children.length, 1);
+
+ var firedOnPost = false;
+ postElement.onFocus.listen((_) {
+ firedOnPost = true;
+ });
+ // Event handlers should not persist to new element.
+ postElement.dispatchEvent(new Event('focus'));
+ expect(firedOnPre, isFalse);
+ expect(firedOnPost, isTrue);
+ });
});
}
diff --git a/tests/html/custom_tags_test.dart b/tests/html/custom_tags_test.dart
new file mode 100644
index 0000000..7ac344c
--- /dev/null
+++ b/tests/html/custom_tags_test.dart
@@ -0,0 +1,46 @@
+// Copyright (c) 2013, 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 custom_tags_test;
+import '../../pkg/unittest/lib/unittest.dart';
+import '../../pkg/unittest/lib/html_config.dart';
+import 'dart:html';
+
+main() {
+ useHtmlConfiguration();
+
+ test('create via custom tag', () {
+ var element = new Element.tag('x-basic1')..id = 'basic1';
+ document.body.nodes.add(element);
+
+ var queryById = query('#basic1');
+ expect(queryById, equals(element));
+
+ var queryByTag = queryAll('x-basic1');
+ expect(queryByTag.length, equals(1));
+ expect(queryByTag[0], equals(element));
+ });
+
+ test('custom inner html', () {
+ var element = new DivElement();
+ element.innerHtml = "<x-basic2 id='basic2'></x-basic2>";
+ document.body.nodes.add(element);
+
+ var queryById = query('#basic2');
+ expect(queryById is Element, isTrue);
+
+ var queryByTag = queryAll('x-basic2');
+ expect(queryByTag.length, equals(1));
+ expect(queryByTag[0], equals(queryById));
+ });
+
+ test('type extension inner html', () {
+ var element = new DivElement();
+ element.innerHtml = "<div is='x-basic3' id='basic3'></div>";
+ document.body.nodes.add(element);
+
+ var queryById = query('#basic3');
+ expect(queryById is DivElement, isTrue);
+ });
+}
diff --git a/tests/html/html.status b/tests/html/html.status
index e03aa5c..03be635 100644
--- a/tests/html/html.status
+++ b/tests/html/html.status
@@ -3,11 +3,21 @@
# BSD-style license that can be found in the LICENSE file.
async_window_test: Skip #TODO(gram): investigating
-
event_test: Skip # Issue 1996
-custom_elements_test: Skip # Not yet implemented.
interactive_test: Skip # Must be run manually.
+# Issue 9326
+custom_elements_test/register: Fail
+custom_elements_test/preregister: Fail
+
+[ $compiler == dart2js ]
+# Document.register is unimplemented.
+custom_elements_test: Skip
+
+[ $compiler == dartanalyzer ]
+# Document.register is unimplemented.
+custom_elements_test: Skip
+
[ $compiler == none && ($runtime == drt || $runtime == dartium) && $mode == debug && $system == macos]
audiobuffersourcenode_test: Pass, Fail, Crash # http://crbug.com/256601
diff --git a/tests/html/serialized_script_value_test.dart b/tests/html/serialized_script_value_test.dart
index afbf04c..af673b6 100644
--- a/tests/html/serialized_script_value_test.dart
+++ b/tests/html/serialized_script_value_test.dart
@@ -36,4 +36,17 @@
serializationTest('simple list', simpleList);
serializationTest('dag list', dagList);
serializationTest('cyclic list', cyclicList);
+
+ serializationTest('datetime', [new DateTime.now()]);
+
+ var blob = new Blob(
+ ['Indescribable... Indestructible! Nothing can stop it!'],
+ 'text/plain');
+ serializationTest('blob', [blob]);
+
+ var canvas = new CanvasElement();
+ canvas.width = 100;
+ canvas.height = 100;
+ var imageData = canvas.context2D.getImageData(0, 0, 1, 1);
+ serializationTest('imagedata', [imageData]);
}
diff --git a/tests/html/svgelement_test.dart b/tests/html/svgelement_test.dart
index 6bc60b0..f94baae 100644
--- a/tests/html/svgelement_test.dart
+++ b/tests/html/svgelement_test.dart
@@ -439,4 +439,14 @@
expect(rect.height, closeTo(100, 1));
});
});
+
+ group('PathElement', () {
+ test('pathSegList', () {
+ svg.PathElement path =
+ new svg.SvgElement.svg('<path d="M 100 100 L 300 100 L 200 300 z"/>');
+ for (var seg in path.pathSegList) {
+ expect(seg is svg.PathSeg, isTrue);
+ }
+ });
+ });
}
diff --git a/tests/html/utils.dart b/tests/html/utils.dart
index 24e7711..38ed073 100644
--- a/tests/html/utils.dart
+++ b/tests/html/utils.dart
@@ -41,6 +41,16 @@
eItems.add(expected);
aItems.add(actual);
+ if (expected is Blob) {
+ expect(actual is Blob, isTrue,
+ reason: '$actual is Blob');
+ expect(expected.type, equals(actual.type),
+ reason: message(path, '.type'));
+ expect(expected.size, equals(actual.size),
+ reason: message(path, '.size'));
+ return;
+ }
+
if (expected is ByteBuffer) {
expect(actual is ByteBuffer, isTrue,
reason: '$actual is ByteBuffer');
@@ -51,6 +61,26 @@
return;
}
+ if (expected is DateTime) {
+ expect(actual is DateTime, isTrue,
+ reason: '$actual is DateTime');
+ expect(expected.millisecondsSinceEpoch,
+ equals(actual.millisecondsSinceEpoch),
+ reason: message(path, '.millisecondsSinceEpoch'));
+ return;
+ }
+
+ if (expected is ImageData) {
+ expect(actual is ImageData, isTrue,
+ reason: '$actual is ImageData');
+ expect(expected.width, equals(actual.width),
+ reason: message(path, '.width'));
+ expect(expected.height, equals(actual.height),
+ reason: message(path, '.height'));
+ walk('$path.data', expected.data, actual.data);
+ return;
+ }
+
if (expected is TypedData) {
expect(actual is TypedData, isTrue,
reason: '$actual is TypedData');
diff --git a/tests/language/allocation_sinking_inlining_test.dart b/tests/language/allocation_sinking_inlining_test.dart
new file mode 100644
index 0000000..9ed27b6
--- /dev/null
+++ b/tests/language/allocation_sinking_inlining_test.dart
@@ -0,0 +1,36 @@
+
+// Copyright (c) 2013, 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.
+// VMOptions=--optimization-counter-threshold=10 --no-use-osr
+
+// Test allocation sinking with polymorphic inlining.
+
+import "package:expect/expect.dart";
+
+class A {
+ foo(x) => ++x.f;
+}
+
+class B {
+ foo(x) => --x.f;
+}
+
+class C {
+ int f = 0;
+}
+
+test(obj) {
+ var c = new C();
+ return obj.foo(c);
+}
+
+main() {
+ var a = new A();
+ var b = new B();
+ Expect.equals(1, test(a));
+ Expect.equals(-1, test(b));
+ for (var i = 0; i < 20; i++) test(a);
+ Expect.equals(1, test(a));
+ Expect.equals(-1, test(b));
+}
diff --git a/tests/language/equality_test.dart b/tests/language/equality_test.dart
index a0faac4..208ed0c 100644
--- a/tests/language/equality_test.dart
+++ b/tests/language/equality_test.dart
@@ -1,7 +1,7 @@
// Copyright (c) 2012, 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.
-// VMOptions=--optimization-counter-threshold=10
+// VMOptions=--optimization-counter-threshold=10 --no-use-osr
import "package:expect/expect.dart";
@@ -53,6 +53,30 @@
}
}
+boolEqualityPositiveA(a) => a == true;
+boolEqualityNegativeA(a) => a != true;
+
+boolEqualityPositiveB(a) => true == a;
+boolEqualityNegativeB(a) => true != a;
+
main() {
- for (int i = 0; i < 20; i++) tests();
+ for (int i = 0; i < 20; i++) {
+ tests();
+ // Do not inline calls to prevent constant folding.
+ Expect.isTrue(boolEqualityPositiveA(true));
+ Expect.isFalse(boolEqualityPositiveA(false));
+ Expect.isFalse(boolEqualityNegativeA(true));
+ Expect.isTrue(boolEqualityNegativeA(false));
+
+ Expect.isTrue(boolEqualityPositiveB(true));
+ Expect.isFalse(boolEqualityPositiveB(false));
+ Expect.isFalse(boolEqualityNegativeB(true));
+ Expect.isTrue(boolEqualityNegativeB(false));
+ }
+
+ // Deoptimize.
+ Expect.isFalse(boolEqualityPositiveA(1));
+ Expect.isTrue(boolEqualityNegativeA("hi"));
+ Expect.isFalse(boolEqualityPositiveB(2.0));
+ Expect.isTrue(boolEqualityNegativeB([]));
}
diff --git a/tests/language/function_subtype_local6_test.dart b/tests/language/function_subtype_local6_test.dart
new file mode 100644
index 0000000..95817d1
--- /dev/null
+++ b/tests/language/function_subtype_local6_test.dart
@@ -0,0 +1,17 @@
+// Copyright (c) 2013, 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.
+// Dart test program for constructors and initializers.
+// VMOptions=--no-eliminate-type-checks
+
+// Regression test for issue 12127.
+
+class C<T> {
+ void test() {
+ void foo(T a) {}
+ }
+}
+
+main() {
+ new C<bool>().test();
+}
diff --git a/tests/language/instanceof3_test.dart b/tests/language/instanceof3_test.dart
index 5075840..746c8bf 100644
--- a/tests/language/instanceof3_test.dart
+++ b/tests/language/instanceof3_test.dart
@@ -5,8 +5,8 @@
import "package:expect/expect.dart";
-// In the type test 'e is T', it is a run-time error if T does not denote a type
-// available in the current lexical scope.
+// In the type test 'e is T', if T does not denote a type available in the
+// current lexical scope, then T is mapped to dynamic and the test succeeds.
isCheckedMode() {
try {
@@ -23,23 +23,23 @@
bool got_type_error = false;
var x = null;
try {
- Expect.isFalse(x is UndeclaredType); // x is null.
+ Expect.isTrue(x is UndeclaredType); // x is null.
} on TypeError catch (error) {
got_type_error = true;
}
- // Type error in production mode and in checked mode.
- Expect.isTrue(got_type_error);
+ // No type error.
+ Expect.isFalse(got_type_error);
}
{
bool got_type_error = false;
var x = 1;
try {
- Expect.isFalse(x is UndeclaredType); // x is not null.
+ Expect.isTrue(x is UndeclaredType); // x is not null.
} on TypeError catch (error) {
got_type_error = true;
}
- // Type error in production mode and in checked mode.
- Expect.isTrue(got_type_error);
+ // No type error.
+ Expect.isFalse(got_type_error);
}
{
bool got_type_error = false;
@@ -49,8 +49,8 @@
} on TypeError catch (error) {
got_type_error = true;
}
- // Type error in checked mode only.
- Expect.isTrue(got_type_error == isCheckedMode());
+ // No type error.
+ Expect.isFalse(got_type_error);
}
{
bool got_type_error = false;
@@ -60,8 +60,8 @@
} on TypeError catch (error) {
got_type_error = true;
}
- // Type error in checked mode only.
- Expect.isTrue(got_type_error == isCheckedMode());
+ // No type error.
+ Expect.isFalse(got_type_error);
}
{
bool got_type_error = false;
@@ -71,8 +71,8 @@
} on TypeError catch (error) {
got_type_error = true;
}
- // Type error in checked mode only.
- Expect.isTrue(got_type_error == isCheckedMode());
+ // No type error.
+ Expect.isFalse(got_type_error);
}
{
bool got_type_error = false;
@@ -82,8 +82,8 @@
} on TypeError catch (error) {
got_type_error = true;
}
- // Type error in checked mode only.
- Expect.isTrue(got_type_error == isCheckedMode());
+ // No type error.
+ Expect.isFalse(got_type_error);
}
}
diff --git a/tests/language/isnot_malformed_type_test.dart b/tests/language/isnot_malformed_type_test.dart
index 593fc75..11abe66 100644
--- a/tests/language/isnot_malformed_type_test.dart
+++ b/tests/language/isnot_malformed_type_test.dart
@@ -1,13 +1,14 @@
// Copyright (c) 2012, 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.
-// Parser throws an error when parsing x is! T with malformed type T.
+
+import 'package:expect/expect.dart';
f(obj) {
- // 'Baz' is not loaded error.
- return (obj is !Baz); /// 01: runtime error
+ // 'Baz' is not loaded, mapped to dynamic.
+ return (obj is !Baz);
}
main () {
- f(null);
+ Expect.isFalse(f(null));
}
diff --git a/tests/language/language.status b/tests/language/language.status
index 67e3e67..e788b73 100644
--- a/tests/language/language.status
+++ b/tests/language/language.status
@@ -80,40 +80,6 @@
const_constructor_mixin2_test/01: Fail # Issue 11917
const_constructor_mixin3_test/01: Fail # Issue 11917
-is_not_class2_test: Fail # Issue 9055
-list_literal_syntax_test/01: Fail # Issue 9055
-list_literal_syntax_test/02: Fail # Issue 9055
-list_literal_syntax_test/03: Fail # Issue 9055
-malformed_inheritance_test/02: Fail # Issue 9055
-malformed_inheritance_test/04: Fail # Issue 9055
-malformed_inheritance_test/06: Fail # Issue 9055
-malformed_test/none: Fail # Issue 9055
-prefix9_test: Fail # Issue 9055
-try_catch_on_syntax_test/07: Fail # Issue 9055
-try_catch_syntax_test/08: Fail # Issue 9055
-type_variable_bounds_test/08: Fail # Issue 9055
-wrong_number_type_arguments_test/01: Fail # Issue 9055
-
-[ $compiler == none && $checked ]
-function_malformed_result_type_test: Fail # Issue 9055
-new_expression_type_args_test/02: Fail # Issue 9055
-prefix16_test: Fail # Issue 9055
-type_parameter_test/01: Fail # Issue 9055
-type_parameter_test/02: Fail # Issue 9055
-type_parameter_test/03: Fail # Issue 9055
-type_parameter_test/04: Fail # Issue 9055
-type_parameter_test/05: Fail # Issue 9055
-type_parameter_test/06: Fail # Issue 9055
-type_variable_bounds_test/07: Fail # Issue 9055
-type_variable_scope2_test: Fail # Issue 9055
-type_variable_scope_test/00: Fail # Issue 9055
-type_variable_scope_test/01: Fail # Issue 9055
-type_variable_scope_test/02: Fail # Issue 9055
-type_variable_scope_test/03: Fail # Issue 9055
-type_variable_scope_test/04: Fail # Issue 9055
-type_variable_scope_test/05: Fail # Issue 9055
-wrong_number_type_arguments_test/02: Fail # Issue 9055
-
[ $compiler == none && $unchecked ]
# Only checked mode reports an error on type assignment
@@ -337,18 +303,6 @@
bound_closure_equality_test: Fail # Issue 10849
-is_not_class2_test: Fail # Issue 9055
-list_literal_syntax_test/01: Fail # Issue 9055
-list_literal_syntax_test/02: Fail # Issue 9055
-list_literal_syntax_test/03: Fail # Issue 9055
-malformed_inheritance_test/02: Fail # Issue 9055
-malformed_inheritance_test/04: Fail # Issue 9055
-malformed_inheritance_test/06: Fail # Issue 9055
-malformed_test/none: Fail # Issue 9055
-try_catch_on_syntax_test/07: Fail # Issue 9055
-try_catch_syntax_test/08: Fail # Issue 9055
-
-
[ $compiler == dart2dart && $minified ]
super_getter_setter_test: Fail # Issue 11065.
diff --git a/tests/language/language_analyzer.status b/tests/language/language_analyzer.status
index 82e8b5f..e977432 100644
--- a/tests/language/language_analyzer.status
+++ b/tests/language/language_analyzer.status
@@ -3,76 +3,15 @@
# BSD-style license that can be found in the LICENSE file.
[ $compiler == dartanalyzer ]
+
+# Runtime negative test. No static errors or warnings.
+closure_call_wrong_argument_count_negative_test: skip
+
+
#argument_definition_test/01: fail # issue 11565 (passing for the wrong reason)
illegal_invocation_test/01: fail # Issue: 11892
-# test issue 11581, it is not warning to call dynamic
-call_through_getter_test: fail
-
-# test issue 11582, non-final field with 'const' constructor
-compile_time_constant10_test/none: fail
-
-# test issue 11583, int is valid key for constant map literal
-compile_time_constant_c_test/01: fail
-
-# test issue 11589, export D from 2 export directives
-export_cyclic_test: fail
-
-# test issue 11580, Function is not a malformed type
-black_listed_test/11: fail
-
-# test issue 11584, positional arguments cannot be used for named parameters
-compile_time_constant_e_test: fail
-
-# test issue 11585, static warning, not negative test
-constructor3_negative_test: fail # issue 11585
-constructor_call_wrong_argument_count_negative_test: fail
-instance_call_wrong_argument_count_negative_test: fail
-
-# test issue 11586, Class(args) is compile-time warning, not error
-constructor_negative_test: fail
-
-# test issue 11590, runtime only negative test
-field_method4_negative_test: fail
-
-# test issue 11591, assigning to the final variable is warning, not error
-final_for_in_variable_test/01: fail
-final_param_negative_test: fail
-final_var_negative_test: fail
-final_variable_assignment_test/01: fail
-final_variable_assignment_test/02: fail
-final_variable_assignment_test/03: fail
-final_variable_assignment_test/04: fail
-getter_no_setter_test/01: fail
-
-# test issue 11592, Function type alias (typedef) is not a constant
-first_class_types_constants_test: fail
-
-# test issue 11594, Reference to a not resolve identifier is static warning
-import_combinators_negative_test: fail
-interface_static_non_final_fields_negative_test: fail
-
-# test issue 11595, It is static warning to create instance (new) of the malformed type
-instantiate_type_variable_negative_test: fail
-
-# test issue 11596. e is Unknown is not a compile time error
-is_not_class2_negative_test: fail
-
-# test issue 11597, It is a compile-time error if part has no "part of" directive
-library_juxtaposition_test: fail
-
-# test issue 11598, Any use of a malbounded type gives rise to a static warning
-mixin_type_parameters_errors_test/01: fail
-mixin_type_parameters_errors_test/02: fail
-mixin_type_parameters_errors_test/05: fail
-
-
-
-
-# TBF: a.imethod = () { return 1; };
-assign_instance_method_negative_test: fail
-
# TBF: m([int p = 'String'])
assign_static_type_test/06: fail
@@ -84,25 +23,14 @@
cast_test/05: fail
# TBF: It is a compile-time error if the superclass of a class C appears in the implements clause of C.
-closure_call_wrong_argument_count_negative_test: fail
const_constructor_super_test/01: fail
compile_time_constant10_test/none: fail
compile_time_constant_c_test/01: fail
-# Runtime negative test. No static errors or warnings.
-closure_call_wrong_argument_count_negative_test: skip
-
# TBF: m([int p = 'String']) and call 'const' instance creation
compile_time_constant_checked2_test/03: fail
compile_time_constant_checked3_test/03: fail
-# TBF: not initialized final instance variable
-constructor2_negative_test: fail
-constructor3_negative_test: fail
-constructor_call_wrong_argument_count_negative_test: fail
-constructor_initializer_test: fail # uses argument definition test
-constructor_negative_test: fail
-
# TBF: It is a static type warning if a type parameter is a supertype of its upper bound.
cyclic_type_variable_test/01: fail
cyclic_type_variable_test/02: fail
@@ -125,54 +53,44 @@
list_literal_syntax_test/02: fail # Issue 12103
list_literal_syntax_test/03: fail # Issue 12103
malformed_test/none: fail
+
+# TBF: disallowed in the most recent spec
named_parameters_aggregated_test/03: fail
-no_such_method_negative_test: fail
+
+# TBF: non-const superinitializer; 7.6.3 Constant Constructors: The superinitializer that appears, explicitly or implicitly, in the initializer list of a constant constructor must specify a constant constructor of the superclass of the immediately enclosing class.
non_const_super_negative_test: fail
+
+# TBF: 1is int; invalid character in number
number_identifier_negative_test: fail
+
+# TBF: we should check conflicts not only for methods, but for accessors too
override_field_test/01: fail
override_field_test/02: fail
override_field_test/03: fail
+
+# TBF: prefix T hidden by type variable T in 'new T.Class()'
prefix10_negative_test: fail
-prefix11_negative_test: fail
-prefix12_negative_test: fail
-prefix1_negative_test: fail
-prefix2_negative_test: fail
-prefix4_negative_test: fail
-prefix5_negative_test: fail
-prefix6_negative_test: fail
-prefix8_negative_test: fail
-prefix9_negative_test: fail
+
+# TBF: no error if A in our library, B extends A in other library, reference B._private from Test extends B in our library.
private_member1_negative_test: fail
private_member2_negative_test: fail
private_member3_negative_test: fail
-pseudo_kw_illegal_test/14: fail
+
+# TBF
pseudo_kw_test: fail
+
+# TBF: hiding at start of the block and declared after declaration statement
scope_negative_test: fail
-static_call_wrong_argument_count_negative_test: fail
+
+# TBF: 'instance.staticMethod()' is static warning
static_field_test/01: fail
static_field_test/02: fail
static_field_test/03: fail
-static_final_field2_negative_test: fail
-static_final_field_negative_test: fail
-syntax_test/28: fail
-syntax_test/29: fail
-syntax_test/30: fail
-syntax_test/31: fail
-syntax_test/32: fail
-syntax_test/33: fail
-throw7_negative_test: fail
-type_error_test: fail
-type_parameter_test/none: fail
-type_variable_bounds2_test/00: fail
-type_variable_bounds2_test/01: fail
-type_variable_bounds2_test/02: fail
-type_variable_bounds2_test/03: fail
-type_variable_bounds2_test/04: fail
-type_variable_bounds2_test/06: fail
-type_variable_static_context_negative_test: fail
-unresolved_in_factory_negative_test: fail
-unresolved_top_level_method_negative_test: fail
-unresolved_top_level_var_negative_test: fail
+
+library_ambiguous_test/04: Fail # TBF: Issue 12106
+
+
+
# test issue 10683, It is a compile-time error if e refers to the name v or the name v=.
block_scope_test: fail
@@ -186,6 +104,7 @@
stack_trace_test: fail
throw3_test: fail
try_catch3_test: fail
+type_error_test: fail
# test issue 10890; on-catch UnknownType is a static warning, not error
try_catch_on_syntax_test/01: fail
@@ -271,10 +190,136 @@
# test issue 11579, assignment, no setter
getter_no_setter_test/none: fail
+# test issue 11580, Function is not a malformed type
+black_listed_test/11: fail
+
+# test issue 11581, it is not warning to call dynamic
+call_through_getter_test: fail
+
+# test issue 11582, non-final field with 'const' constructor
+compile_time_constant10_test/none: fail
+
+# test issue 11583, int is valid key for constant map literal
+compile_time_constant_c_test/01: fail
+
+# test issue 11584, positional arguments cannot be used for named parameters
+compile_time_constant_e_test: fail
+
+# test issue 11585, static warning, not negative test
+constructor3_negative_test: fail
+constructor_call_wrong_argument_count_negative_test: fail
+instance_call_wrong_argument_count_negative_test: fail
+
+# test issue 11586, Class(args) is compile-time warning, not error
+constructor_negative_test: fail
+
+# test issue 11589, export D from 2 export directives
+export_cyclic_test: fail
+
+# test issue 11590, runtime only negative test
+field_method4_negative_test: fail
+
+# test issue 11591, assigning to the final variable is warning, not error
+final_for_in_variable_test/01: fail
+final_param_negative_test: fail
+final_var_negative_test: fail
+final_variable_assignment_test/01: fail
+final_variable_assignment_test/02: fail
+final_variable_assignment_test/03: fail
+final_variable_assignment_test/04: fail
+getter_no_setter_test/01: fail
+
+# test issue 11592, Function type alias (typedef) is not a constant
+first_class_types_constants_test: fail
+
+# test issue 11594, Reference to a not resolve identifier is static warning
+import_combinators_negative_test: fail
+interface_static_non_final_fields_negative_test: fail
+
+# test issue 11595, It is static warning to create instance (new) of the malformed type
+instantiate_type_variable_negative_test: fail
+
+# test issue 11596. e is Unknown is not a compile time error
+is_not_class2_negative_test: fail
+
+# test issue 11597, It is a compile-time error if part has no "part of" directive
+library_juxtaposition_test: fail
+
+# test issue 11598, Any use of a malbounded type gives rise to a static warning
+mixin_type_parameters_errors_test/01: fail
+mixin_type_parameters_errors_test/02: fail
+mixin_type_parameters_errors_test/05: fail
+
+# test issue 11698, no setter, so warning, not error
+assign_instance_method_negative_test: fail
+
# test issue 11918: mixin and const constructor
const_constructor_mixin_test/01: fail
const_constructor_mixin3_test/01: fail
+# test issue 11958, fails only at runtime
+no_such_method_negative_test: fail
+
+# test issue 11962, it is warning, not error to reference undeclared identifier
+prefix1_negative_test: fail
+prefix2_negative_test: fail
+prefix4_negative_test: fail
+prefix5_negative_test: fail
+prefix12_negative_test: fail
+
+# test issue 11963, it is fine to access any property of the dynamic variable
+prefix6_negative_test: fail
+
+# test issue 11964, Any use of a malformed type gives rise to a static warning.
+prefix8_negative_test: fail
+prefix9_negative_test: fail
+prefix11_negative_test: fail
+
+# test issue 11965, 'source' is not built-in identifier anymore
+pseudo_kw_illegal_test/14: fail
+
+# test issue 12156, fails only at runtime
+static_call_wrong_argument_count_negative_test: fail
+
+# test issue 12157, uninitializer instance variable is warning, so not negative test
+static_final_field_negative_test: fail
+constructor2_negative_test: fail
+
+# test issue 12158, 'native' is not in spec, so analyzer does not generate compile-time error
+syntax_test/28: fail
+syntax_test/29: fail
+syntax_test/30: fail
+syntax_test/31: fail
+syntax_test/32: fail
+syntax_test/33: fail
+
+# test issue 12159, print(exception.message_); causes static warning, not an error
+throw7_negative_test: fail
+
+# test issue 12160, not annotated warnings for type variables from static member
+type_parameter_test/none: fail
+# test issue 12161, type variable in static, malformed type, static warning
+type_variable_static_context_negative_test: fail
+
+# test issue 12162, 'a' has dynamic type, so it statically it is assignable to anything
+type_variable_bounds2_test/00: fail
+type_variable_bounds2_test/01: fail
+type_variable_bounds2_test/02: fail
+type_variable_bounds2_test/03: fail
+type_variable_bounds2_test/04: fail
+type_variable_bounds2_test/06: fail
+
+# test issue 12163, unresolved identifier is static warning in static context
+unresolved_in_factory_negative_test: fail
+unresolved_top_level_method_negative_test: fail
+unresolved_top_level_var_negative_test: fail
+
+# test issue 12181, uses argument definition test
+constructor_initializer_test: fail
+
+# test issue 12184, It is static warning, not error, to assign to a constant variable.
+static_final_field2_negative_test: fail
+
[ $compiler == dartanalyzer && $checked ]
factory1_test/00: fail
factory1_test/01: fail
diff --git a/tests/language/language_dart2js.status b/tests/language/language_dart2js.status
index fa07442..528d5e9 100644
--- a/tests/language/language_dart2js.status
+++ b/tests/language/language_dart2js.status
@@ -29,6 +29,11 @@
constructor_initializer_test: Fail, OK # Depends on ?parameter check.
+# Issues related to undeclared prefix resolution.
+malformed_test/none: Fail
+malformed_test/05: Fail
+malformed_test/06: Fail
+
# Fails due to inlining. Not all expected frames are in the trace.
full_stacktrace1_test: Pass, Fail # issue 9895
full_stacktrace2_test: Pass, Fail # issue 9895
@@ -110,7 +115,6 @@
call_nonexistent_constructor_test: Fail
constructor_named_arguments_test/01: Fail # http://dartbug.com/5519
getter_no_setter_test/01: Fail # http://dartbug.com/5519
-isnot_malformed_type_test/01: Fail # http://dartbug.com/5519
not_enough_positional_arguments_test/01: Fail # http://dartbug.com/5519
error_stacktrace_test: Fail # (Issue 11681).
@@ -163,10 +167,6 @@
mixin_type_parameters_errors_test/02: Fail
mixin_type_parameters_errors_test/05: Fail
-# new with wrong number of type arguments should be a runtime error.
-mixin_type_parameters_errors_test/03: Fail
-mixin_type_parameters_errors_test/04: Fail
-
# External tests.
external_test/01: Fail
external_test/02: Fail
@@ -184,7 +184,6 @@
# Implementation errors (library or generated code).
-instanceof3_test: Fail # cannot resolve type UndeclaredType.
instanceof4_test: Fail # Expect.isTrue(false) fails.
list_literal4_test: Fail # Illegal argument(s): 0 -- checked mode test.
map_literal4_test: Fail # Attempt to modify an immutable object -- checked mode test.
diff --git a/tests/language/library_ambiguous_test.dart b/tests/language/library_ambiguous_test.dart
index 75d2fda..cb02c8d 100644
--- a/tests/language/library_ambiguous_test.dart
+++ b/tests/language/library_ambiguous_test.dart
@@ -17,7 +17,7 @@
print(bar()); /// 01: compile-time error
print(baz()); /// 02: compile-time error
print(bay()); /// 03: compile-time error
- print(main is bax); /// 04: compile-time error
+ print(main is bax); /// 04: static type warning
var x = new X(); /// 05: continued
print("No error expected if ambiguous definitions are not used.");
}
diff --git a/tests/language/malformed_test.dart b/tests/language/malformed_test.dart
index eb2834a..8f15dff 100644
--- a/tests/language/malformed_test.dart
+++ b/tests/language/malformed_test.dart
@@ -6,6 +6,7 @@
// wrong number of type arguments are handled as raw types.
import 'package:expect/expect.dart';
+import 'package:expect/expect.dart' as prefix; // Define 'prefix'.
checkIsUnresolved(var v) {
Expect.isTrue(v is Unresolved);
@@ -76,8 +77,7 @@
checkIsListDynamic(true, []);
checkIsListDynamic(true, <>[]); /// 01: compile-time error
-// TODO(johnniwinther): Create runtime type information on literal lists.
-// checkIsListDynamic(false, <int>[]);
+ checkIsListDynamic(false, <int>[]);
checkIsListDynamic(true, <Unresolved>[]);
checkIsListDynamic(true, <Unresolved<int>>[]);
checkIsListDynamic(true, <prefix.Unresolved>[]);
@@ -92,16 +92,16 @@
checkIsListDynamic(true, new List<prefix.Unresolved<int>>());
checkIsListDynamic(true, new List<int, String>());
+ checkIsMapDynamic(true, true, <dynamic, dynamic>{});
checkIsMapDynamic(true, true, {});
checkIsMapDynamic(true, true, <>{}); /// 03: compile-time error
checkIsMapDynamic(true, true, <int>{});
-// TODO(johnniwinther): Create runtime type information on literal maps.
-// checkIsMapDynamic(false, false, <String, int>{});
+ checkIsMapDynamic(false, false, <String, int>{});
checkIsMapDynamic(true, true, <String, int, String>{});
-// checkIsMapDynamic(true, false, <Unresolved, int>{});
-// checkIsMapDynamic(false, true, <String, Unresolved<int>>{});
-// checkIsMapDynamic(true, false, <prefix.Unresolved, int>{});
-// checkIsMapDynamic(false, true, <String, prefix.Unresolved<int>>{});
+ checkIsMapDynamic(true, false, <Unresolved, int>{});
+ checkIsMapDynamic(false, true, <String, Unresolved<int>>{});
+ checkIsMapDynamic(true, false, <prefix.Unresolved, int>{});
+ checkIsMapDynamic(false, true, <String, prefix.Unresolved<int>>{});
checkIsMapDynamic(true, true, new Map());
checkIsMapDynamic(true, true, new Map<>); /// 04: compile-time error
@@ -118,28 +118,36 @@
Expect.throws(() => new prefix.Unresolved(), (e) => true);
Expect.throws(() => new prefix.Unresolved<int>(), (e) => true);
+ // The expression 'undeclared_prefix.Unresolved()' is parsed as the invocation
+ // of the named constructor 'Unresolved' on the type 'undeclared_prefix'.
+ Expect.throws(() => new undeclared_prefix.Unresolved(), (e) => true);
+ // The expression 'undeclared_prefix.Unresolved<int>' cannot be parsed.
+ Expect.throws(() => new undeclared_prefix.Unresolved<int>(), (e) => true); /// 05: compile-time error
+
try {
throw 'foo';
} on Unresolved catch (e) {
- } catch (e) {
- Expect.fail();
+ // Equivalent to 'on dynamic', catches 'foo'.
}
try {
throw 'foo';
} on Unresolved<int> catch (e) {
- } catch (e) {
- Expect.fail();
+ // Equivalent to 'on dynamic', catches 'foo'.
}
try {
throw 'foo';
} on prefix.Unresolved catch (e) {
- } catch (e) {
- Expect.fail();
+ // Equivalent to 'on dynamic', catches 'foo'.
}
try {
throw 'foo';
} on prefix.Unresolved<int> catch (e) {
- } catch (e) {
- Expect.fail();
+ // Equivalent to 'on dynamic', catches 'foo'.
+ }
+ try {
+ throw 'foo';
+ }
+ on undeclared_prefix.Unresolved<int> /// 06: compile-time error
+ catch (e) {
}
}
\ No newline at end of file
diff --git a/tests/language/mixin_type_parameters_errors_test.dart b/tests/language/mixin_type_parameters_errors_test.dart
index 7938160..be459bd 100644
--- a/tests/language/mixin_type_parameters_errors_test.dart
+++ b/tests/language/mixin_type_parameters_errors_test.dart
@@ -16,7 +16,7 @@
var a;
a = new A();
a = new A<int>();
- a = new A<String, String>(); /// 03: static type warning, runtime error
+ a = new A<String, String>(); /// 03: static type warning
a = new F<int>();
- a = new F<int, String>(); /// 04: static type warning, runtime error
+ a = new F<int, String>(); /// 04: static type warning
}
\ No newline at end of file
diff --git a/tests/lib/analyzer/analyze_tests.status b/tests/lib/analyzer/analyze_tests.status
index 4011835..802f246 100644
--- a/tests/lib/analyzer/analyze_tests.status
+++ b/tests/lib/analyzer/analyze_tests.status
@@ -3,7 +3,7 @@
# BSD-style license that can be found in the LICENSE file.
[ $compiler == dartanalyzer ]
-53bit_overflow_literal_test/01: fail, ok
+javascript_int_overflow_literal_test/01: fail, ok
# https://code.google.com/p/dart/issues/detail?id=11665
standalone/assert_test: fail
@@ -32,7 +32,7 @@
[ $compiler == dart2analyzer ]
-53bit_overflow_literal_test/01: fail, ok
+javascript_int_overflow_literal_test/01: fail, ok
# https://code.google.com/p/dart/issues/detail?id=11665
standalone/assert_test: fail
diff --git a/tests/lib/lib.status b/tests/lib/lib.status
index faa078e..0690589 100644
--- a/tests/lib/lib.status
+++ b/tests/lib/lib.status
@@ -4,10 +4,14 @@
[ $compiler == dart2js ]
math/*: Skip
+mirrors/class_mirror_type_variables_test: Fail # Issue 12087
+mirrors/invoke_private_test: Fail # Issue 12164
+mirrors/function_type_mirror_test: Fail # Issue 12166
mirrors/method_mirror_name_test: Fail # Issue 6335
mirrors/method_mirror_properties_test: Fail # Issue 11861
mirrors/method_mirror_returntype_test : Fail # Issue 11928
mirrors/mirrors_test: Fail # TODO(ahe): I'm working on fixing this.
+mirrors/null_test : Fail # Issue 12129
mirrors/library_uri_io_test: Skip # Not intended for dart2js as it uses dart:io.
async/run_async3_test: Fail # _enqueueImmediate runs after Timer. http://dartbug.com/9002
async/run_async4_test: Pass, Fail # no global exception handler in isolates. http://dartbug.com/9012
@@ -89,13 +93,14 @@
mirrors/library_metadata_test: Fail # http://dartbug.com/10906
mirrors/parameter_test: Fail # http://dartbug.com/11567
mirrors/operator_test: Fail # http://dartbug.com/11944
-mirrors/local_isolate_test: Fail # http://dartbug.com/12026
+mirrors/null_test: Fail # Issue 12128
[ $compiler == none && $runtime == drt ]
async/timer_isolate_test: Skip # See Issue 4997
async/timer_not_available_test: Skip # only meant to test when there is no way to
# implement timer (currently only in d8)
mirrors/library_uri_io_test: Skip # Not intended for drt as it uses dart:io.
+mirrors/local_isolate_test: Skip # http://dartbug.com/12188
async/run_async6_test: Fail # Issue 10910
[ $compiler == none && $runtime == drt && $system == windows ]
@@ -107,3 +112,4 @@
[ $arch == simmips ]
convert/chunked_conversion_utf88_test: Pass, Slow # Issue 12025.
+convert/streamed_conversion_json_utf8_decode_test: Pass, Slow
diff --git a/tests/lib/mirrors/class_mirror_type_variables_test.dart b/tests/lib/mirrors/class_mirror_type_variables_test.dart
new file mode 100644
index 0000000..2b02bad
--- /dev/null
+++ b/tests/lib/mirrors/class_mirror_type_variables_test.dart
@@ -0,0 +1,33 @@
+// Copyright (c) 2013, 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 "dart:mirrors";
+
+import "package:expect/expect.dart";
+
+class C<R,S,T> {
+ R foo(R r) => r;
+ S bar(S s) => s;
+ T baz(T t) => t;
+}
+
+class NoTypeParams {}
+
+main() {
+ ClassMirror cm;
+ cm = reflectClass(C);
+ Expect.equals(3, cm.typeVariables.length);
+ Expect.equals(true, cm.typeVariables.containsKey(const Symbol("R")));
+ Expect.equals(true, cm.typeVariables.containsKey(const Symbol("S")));
+ Expect.equals(true, cm.typeVariables.containsKey(const Symbol("T")));
+ var values = cm.typeVariables.values;
+ values.forEach((e) {
+ Expect.equals(true, e is TypeVariableMirror);
+ });
+ Expect.equals(const Symbol("R"), values.elementAt(0).simpleName);
+ Expect.equals(const Symbol("S"), values.elementAt(1).simpleName);
+ Expect.equals(const Symbol("T"), values.elementAt(2).simpleName);
+ cm = reflectClass(NoTypeParams);
+ Expect.equals(cm.typeVariables.length, 0);
+}
diff --git a/tests/lib/mirrors/function_type_mirror_test.dart b/tests/lib/mirrors/function_type_mirror_test.dart
new file mode 100644
index 0000000..4376c83
--- /dev/null
+++ b/tests/lib/mirrors/function_type_mirror_test.dart
@@ -0,0 +1,23 @@
+// Copyright (c) 2013, 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 "dart:mirrors";
+
+import "package:expect/expect.dart";
+
+typedef void FooFunction(int a, double b);
+
+bar(int a) {}
+
+main() {
+ TypedefMirror tm = reflectClass(FooFunction);
+ FunctionTypeMirror ftm = tm.referent;
+ Expect.equals(const Symbol("void"), ftm.returnType.simpleName);
+ Expect.equals(const Symbol("int"), ftm.parameters[0].type.simpleName);
+ Expect.equals(const Symbol("double"), ftm.parameters[1].type.simpleName);
+ ClosureMirror cm = reflect(bar);
+ ftm = cm.type;
+ Expect.equals(const Symbol("dynamic"), ftm.returnType.simpleName);
+ Expect.equals(const Symbol("int"), ftm.parameters[0].type.simpleName);
+}
diff --git a/tests/lib/mirrors/invoke_private_test.dart b/tests/lib/mirrors/invoke_private_test.dart
new file mode 100644
index 0000000..cac9f1e
--- /dev/null
+++ b/tests/lib/mirrors/invoke_private_test.dart
@@ -0,0 +1,86 @@
+// Copyright (c) 2013, 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 test.invoke_test;
+
+import 'dart:mirrors';
+
+import 'package:expect/expect.dart';
+import '../../async_helper.dart';
+
+class C {
+ var _field;
+ C() : this._field = 'default';
+ C._named(this._field);
+
+ get _getter => 'get $_field';
+ set _setter(v) => _field = 'set $v';
+ _method(x, y, z) => '$x+$y+$z';
+
+ static var _staticField = 'initial';
+ static get _staticGetter => 'sget $_staticField';
+ static set _staticSetter(v) => _staticField = 'sset $v';
+ static _staticFunction(x, y) => "($x,$y)";
+}
+
+var _libraryField = 'a priori';
+get _libraryGetter => 'lget $_libraryField';
+set _librarySetter(v) => _libraryField = 'lset $v';
+_libraryFunction(x,y) => '$x$y';
+
+main() {
+ var result;
+
+ // InstanceMirror.
+ C c = new C();
+ InstanceMirror im = reflect(c);
+ result = im.invoke(const Symbol('_method'), [2,4,8]);
+ Expect.equals('2+4+8', result.reflectee);
+
+ result = im.getField(const Symbol('_getter'));
+ Expect.equals('get default', result.reflectee);
+ result = im.getField(const Symbol('_field'));
+ Expect.equals('default', result.reflectee);
+
+ im.setField(const Symbol('_setter'), 'foo');
+ Expect.equals('set foo', c._field);
+ im.setField(const Symbol('_field'), 'bar');
+ Expect.equals('bar', c._field);
+
+
+ // ClassMirror.
+ ClassMirror cm = reflectClass(C);
+ result = cm.invoke(const Symbol('_staticFunction'),[3,4]);
+ Expect.equals('(3,4)', result.reflectee);
+
+ result = cm.getField(const Symbol('_staticGetter'));
+ Expect.equals('sget initial', result.reflectee);
+ result = cm.getField(const Symbol('_staticField'));
+ Expect.equals('initial', result.reflectee);
+
+ cm.setField(const Symbol('_staticSetter'), 'sfoo');
+ Expect.equals('sset sfoo', C._staticField);
+ cm.setField(const Symbol('_staticField'), 'sbar');
+ Expect.equals('sbar', C._staticField);
+
+ result = cm.newInstance(const Symbol('_named'), ['my value']);
+ Expect.isTrue(result.reflectee is C);
+ Expect.equals('my value', result.reflectee._field);
+
+
+ // LibraryMirror.
+ LibraryMirror lm = cm.owner;
+ result = lm.invoke(const Symbol('_libraryFunction'),[':',')']);
+ Expect.equals(':)', result.reflectee);
+
+ result = lm.getField(const Symbol('_libraryGetter'));
+ Expect.equals('lget a priori', result.reflectee);
+ result = lm.getField(const Symbol('_libraryField'));
+ Expect.equals('a priori', result.reflectee);
+
+ lm.setField(const Symbol('_librarySetter'), 'lfoo');
+ Expect.equals('lset lfoo', _libraryField);
+ lm.setField(const Symbol('_libraryField'), 'lbar');
+ Expect.equals('lbar', _libraryField);
+}
diff --git a/tests/lib/mirrors/null_test.dart b/tests/lib/mirrors/null_test.dart
new file mode 100644
index 0000000..9142c6d
--- /dev/null
+++ b/tests/lib/mirrors/null_test.dart
@@ -0,0 +1,31 @@
+// Copyright (c) 2013, 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 test.null_test;
+
+import 'dart:mirrors';
+
+import 'package:expect/expect.dart';
+
+main() {
+ InstanceMirror nullMirror = reflect(null);
+ Expect.isTrue(nullMirror.getField(const Symbol('hashCode')).reflectee is int);
+ Expect.equals('Null',
+ nullMirror.getField(const Symbol('runtimeType')).reflectee
+ .toString());
+ Expect.isTrue(nullMirror.invoke(const Symbol('=='), [null]).reflectee);
+ Expect.isFalse(nullMirror.invoke(const Symbol('=='), [new Object()])
+ .reflectee);
+ Expect.equals('null',
+ nullMirror.invoke(const Symbol('toString'), []).reflectee);
+ Expect.throws(() => nullMirror.invoke(const Symbol('notDefined'), []),
+ (e) => e is NoSuchMethodError,
+ 'noSuchMethod');
+
+ ClassMirror NullMirror = nullMirror.type;
+ Expect.equals(const Symbol('Null'), NullMirror.simpleName);
+ Expect.equals(const Symbol('Object'), NullMirror.superclass.simpleName);
+ Expect.equals(null, NullMirror.superclass.superclass);
+ Expect.equals(null, NullMirror.owner); // Null belongs to no library.
+}
diff --git a/tests/lib/typed_data/float32x4_cross_test.dart b/tests/lib/typed_data/float32x4_cross_test.dart
new file mode 100644
index 0000000..0816846
--- /dev/null
+++ b/tests/lib/typed_data/float32x4_cross_test.dart
@@ -0,0 +1,50 @@
+// Copyright (c) 2013, 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.
+// VMOptions=--optimization-counter-threshold=10
+
+// Library tag to be able to run in html test framework.
+library float32x4_cross_test;
+
+import 'dart:typed_data';
+import 'package:expect/expect.dart';
+
+Float32x4 cross(Float32x4 a, Float32x4 b) {
+ var t0 = a.yzxw;
+ var t1 = b.zxyw;
+ var l = t0 * t1;
+ t0 = a.zxyw;
+ t1 = b.yzxw;
+ var r = t0 * t1;
+ return l-r;
+}
+
+void testCross(Float32x4 a, Float32x4 b, Float32x4 r) {
+ var x = cross(a, b);
+ Expect.equals(r.x, x.x);
+ Expect.equals(r.y, x.y);
+ Expect.equals(r.z, x.z);
+ Expect.equals(r.w, x.w);
+}
+
+main() {
+ var x = new Float32x4(1.0, 0.0, 0.0, 0.0);
+ var y = new Float32x4(0.0, 1.0, 0.0, 0.0);
+ var z = new Float32x4(0.0, 0.0, 1.0, 0.0);
+ var zero = new Float32x4.zero();
+
+ for (int i = 0; i < 20; i++) {
+ testCross(x, y, z);
+ testCross(z, x, y);
+ testCross(y, z, x);
+ testCross(z, y, -x);
+ testCross(x, z, -y);
+ testCross(y, x, -z);
+ testCross(x, x, zero);
+ testCross(y, y, zero);
+ testCross(z, z, zero);
+ testCross(x, y, cross(-y, x));
+ testCross(x, y+z, cross(x, y) + cross(x, z));
+ }
+}
+
diff --git a/tests/lib/typed_data/float32x4_transpose_test.dart b/tests/lib/typed_data/float32x4_transpose_test.dart
new file mode 100644
index 0000000..f408d74
--- /dev/null
+++ b/tests/lib/typed_data/float32x4_transpose_test.dart
@@ -0,0 +1,62 @@
+// Copyright (c) 2013, 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.
+// VMOptions=--optimization-counter-threshold=10
+
+// Library tag to be able to run in html test framework.
+library float32x4_transpose_test;
+
+import 'dart:typed_data';
+import 'package:expect/expect.dart';
+
+void transpose(Float32x4List m) {
+ Expect.equals(4, m.length);
+ var m0 = m[0];
+ var m1 = m[1];
+ var m2 = m[2];
+ var m3 = m[3];
+ var t0 = m0.interleaveXY(m1);
+ var t1 = m2.interleaveXY(m3);
+ var t2 = m0.interleaveZW(m1);
+ var t3 = m2.interleaveZW(m3);
+ m[0] = t0.interleaveXYPairs(t1);
+ m[1] = t0.interleaveZWPairs(t1);
+ m[2] = t2.interleaveXYPairs(t3);
+ m[3] = t2.interleaveZWPairs(t3);
+}
+
+void testTranspose(Float32x4List m, Float32x4List r) {
+ transpose(m); // In place transpose.
+ for (int i = 0; i < 4; i++) {
+ var a = m[i];
+ var b = r[i];
+ Expect.equals(b.x, a.x);
+ Expect.equals(b.y, a.y);
+ Expect.equals(b.z, a.z);
+ Expect.equals(b.w, a.w);
+ }
+}
+
+main() {
+ var A = new Float32x4List(4);
+ A[0] = new Float32x4(1.0, 2.0, 3.0, 4.0);
+ A[1] = new Float32x4(5.0, 6.0, 7.0, 8.0);
+ A[2] = new Float32x4(9.0, 10.0, 11.0, 12.0);
+ A[3] = new Float32x4(13.0, 14.0, 15.0, 16.0);
+ var B = new Float32x4List(4);
+ B[0] = new Float32x4(1.0, 5.0, 9.0, 13.0);
+ B[1] = new Float32x4(2.0, 6.0, 10.0, 14.0);
+ B[2] = new Float32x4(3.0, 7.0, 11.0, 15.0);
+ B[3] = new Float32x4(4.0, 8.0, 12.0, 16.0);
+ var I = new Float32x4List(4);
+ I[0] = new Float32x4(1.0, 0.0, 0.0, 0.0);
+ I[1] = new Float32x4(0.0, 1.0, 0.0, 0.0);
+ I[2] = new Float32x4(0.0, 0.0, 1.0, 0.0);
+ I[3] = new Float32x4(0.0, 0.0, 0.0, 1.0);
+ for (int i = 0; i < 20; i++) {
+ var m = new Float32x4List.fromList(I);
+ testTranspose(m, I);
+ m = new Float32x4List.fromList(A);
+ testTranspose(m, B);
+ }
+}
diff --git a/tests/lib/typed_data/float32x4_two_arg_shuffle_test.dart b/tests/lib/typed_data/float32x4_two_arg_shuffle_test.dart
index f991356..5186b60 100644
--- a/tests/lib/typed_data/float32x4_two_arg_shuffle_test.dart
+++ b/tests/lib/typed_data/float32x4_two_arg_shuffle_test.dart
@@ -1,6 +1,7 @@
// Copyright (c) 2013, 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.
+// VMOptions=--optimization-counter-threshold=10
// Library tag to be able to run in html test framework.
library float32x4_two_arg_shuffle_test;
@@ -59,7 +60,7 @@
}
main() {
- for (int i = 0; i < 4000; i++) {
+ for (int i = 0; i < 20; i++) {
testWithZWInXY();
testInterleaveXY();
testInterleaveZW();
diff --git a/tests/standalone/53bit_overflow_test.dart b/tests/standalone/53bit_overflow_test.dart
deleted file mode 100644
index 3bbc6e3..0000000
--- a/tests/standalone/53bit_overflow_test.dart
+++ /dev/null
@@ -1,118 +0,0 @@
-// Copyright (c) 2013, 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.
-
-// VMOptions=--throw_on_javascript_int_overflow --optimization_counter_threshold=10
-
-
-import "package:expect/expect.dart";
-import 'dart:typed_data';
-
-
-double dti_arg;
-int double_to_int() {
- return dti_arg.toInt();
-}
-
-
-int ia_arg1;
-int ia_arg2;
-int integer_add() {
- return ia_arg1 + ia_arg2;
-}
-
-
-int is_arg;
-int integer_shift() {
- return is_arg << 1;
-}
-
-
-int max_add_throws() {
- return 0xFFFFFFFFFFFFF + 1;
-}
-
-
-int min_sub_throws() {
- return -0xFFFFFFFFFFFFF - 2;
-}
-
-
-int n_arg;
-int negate() {
- return -n_arg;
-}
-
-
-int max_literal() {
- return 0xFFFFFFFFFFFFF;
-}
-
-
-int min_literal() {
- var min_literal = -0xFFFFFFFFFFFFF - 1;
- return min_literal;
-}
-
-// We don't test for the _FiftyThreeBitOverflowError since it's not visible.
-// It's should not be visible since it doesn't exist on dart2js.
-bool is53BitError(e) => e is Error && "$e".startsWith("53-bit Overflow:");
-
-main() {
- Expect.equals(0xFFFFFFFFFFFFF, max_literal());
- Expect.equals(-0xFFFFFFFFFFFFF - 1, min_literal());
-
- // Run the tests once before optimizations.
- dti_arg = 1.9e16;
- Expect.throws(double_to_int, is53BitError);
-
- ia_arg1 = (1 << 51);
- ia_arg2 = (1 << 51);
- Expect.throws(integer_add, is53BitError);
-
- n_arg = -0xFFFFFFFFFFFFF - 1;
- Expect.throws(negate, is53BitError);
-
- is_arg = (1 << 51);
- Expect.throws(integer_shift, is53BitError);
-
- Expect.throws(max_add_throws, is53BitError);
- Expect.throws(min_sub_throws, is53BitError);
-
- for (int i = 0; i < 20; i++) {
- dti_arg = i.toDouble();
- // Expect.throws calls through the closure, so we have to here, too.
- var f = double_to_int;
- Expect.equals(i, f());
-
- ia_arg1 = i;
- ia_arg2 = i;
- f = integer_add;
- Expect.equals(i + i, f());
-
- n_arg = i;
- f = negate;
- Expect.equals(-i, f());
-
- is_arg = i;
- f = integer_shift;
- Expect.equals(i << 1, f());
- }
-
- // The optimized functions should now deoptimize and throw the error.
- dti_arg = 1.9e16;
- Expect.throws(double_to_int, is53BitError);
-
- ia_arg1 = (1 << 51);
- ia_arg2 = (1 << 51);
- Expect.throws(integer_add, is53BitError);
-
- n_arg = -0xFFFFFFFFFFFFF - 1;
- Expect.throws(negate, is53BitError);
-
- is_arg = (1 << 51);
- Expect.throws(integer_shift, is53BitError);
-
- Expect.throws(max_add_throws, is53BitError);
- Expect.throws(min_sub_throws, is53BitError);
-}
diff --git a/tests/standalone/io/certificate_test.dart b/tests/standalone/io/certificate_test.dart
new file mode 100644
index 0000000..fb5b423
--- /dev/null
+++ b/tests/standalone/io/certificate_test.dart
@@ -0,0 +1,38 @@
+// Copyright (c) 2013, 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.
+
+// This test verifies that a server certificate can be verified by a client
+// that loads the certificate authority certificate it depends on at runtime.
+
+import "package:path/path.dart";
+import "dart:io";
+import "dart:async";
+
+String scriptDir = dirname(new Options().script);
+
+void main() {
+ SecureSocket.initialize(database: join(scriptDir, 'pkcert'),
+ password: 'dartdart');
+ runServer().then((SecureServerSocket server) {
+ return Process.run(new Options().executable,
+ ['--checked',
+ join(scriptDir, 'certificate_test_client.dart'),
+ server.port.toString(),
+ join(scriptDir, 'pkcert', 'myauthority.pem')]);
+ }).then((ProcessResult result) {
+ if (result.exitCode != 0) {
+ print("Client failed with exit code ${result.exitCode}");
+ print(" stdout:");
+ print(result.stdout);
+ print(" stderr:");
+ print(result.stderr);
+ throw new AssertionError();
+ }
+ });
+}
+
+Future<SecureServerSocket> runServer() =>
+ SecureServerSocket.bind("localhost", 0, "localhost_cert")
+ .then((server) => server..listen(
+ (socket) => socket.pipe(socket).then((_) => server.close())));
diff --git a/tests/standalone/io/certificate_test_client.dart b/tests/standalone/io/certificate_test_client.dart
new file mode 100644
index 0000000..f7f2fb2
--- /dev/null
+++ b/tests/standalone/io/certificate_test_client.dart
@@ -0,0 +1,41 @@
+// Copyright (c) 2013, 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.
+//
+// Client that tests that a certificate authority certificate loaded
+// at runtime can be used to verify a certificate chain. The server it
+// connects to uses localhost_cert, signed by myauthority_cert, to connect
+// securely.
+
+import 'dart:io';
+
+void main() {
+ int port = int.parse(new Options().arguments[0]);
+ String certificate = new Options().arguments[1];
+ SecureSocket.initialize();
+ var mycert = new File(certificate).readAsBytesSync();
+ bool threw = false;
+ try {
+ SecureSocket.addCertificate("I am not a cert".codeUnits,
+ SecureSocket.TRUST_ISSUE_SERVER_CERTIFICATES);
+ } on CertificateException catch (e) {
+ threw = true;
+ }
+ if (!threw) throw new AssertException("Expected bad certificate to throw");
+
+ threw = false;
+ try {
+ SecureSocket.addCertificate(mycert, "Trust me, I'm a string");
+ } on CertificateException catch (e) {
+ threw = true;
+ }
+ if (!threw) throw new AssertException("Expected bad trust string to throw");
+
+ SecureSocket.addCertificate(mycert,
+ SecureSocket.TRUST_ISSUE_SERVER_CERTIFICATES);
+ SecureSocket.connect('localhost', port).then((SecureSocket socket) {
+ socket.writeln("hello world");
+ socket.listen((data) { });
+ socket.close();
+ });
+}
diff --git a/tests/standalone/io/directory_fuzz_test.dart b/tests/standalone/io/directory_fuzz_test.dart
index dda9fe3..fb66b94 100644
--- a/tests/standalone/io/directory_fuzz_test.dart
+++ b/tests/standalone/io/directory_fuzz_test.dart
@@ -8,6 +8,7 @@
import 'dart:async';
import 'dart:io';
import 'dart:isolate';
+import "package:expect/expect.dart";
import 'fuzz_support.dart';
@@ -39,6 +40,11 @@
var port = new ReceivePort();
var futures = [];
typeMapping.forEach((k, v) {
+ if (v is! String) {
+ Expect.throws(() => new Directory(v),
+ (e) => e is ArgumentError);
+ return;
+ }
var d = new Directory(v);
futures.add(doItAsync(d.exists));
futures.add(doItAsync(d.create));
diff --git a/tests/standalone/io/directory_invalid_arguments_test.dart b/tests/standalone/io/directory_invalid_arguments_test.dart
index 29f96c8..1b35aa0 100644
--- a/tests/standalone/io/directory_invalid_arguments_test.dart
+++ b/tests/standalone/io/directory_invalid_arguments_test.dart
@@ -22,29 +22,13 @@
}
void testInvalidArguments() {
- Directory d = new Directory(12);
try {
- d.existsSync();
+ Directory d = new Directory(12);
Expect.fail("No exception thrown");
} catch (e) {
Expect.isTrue(e is ArgumentError);
}
- try {
- d.deleteSync();
- Expect.fail("No exception thrown");
- } catch (e) {
- Expect.isTrue(e is ArgumentError);
- }
- try {
- d.createSync();
- Expect.fail("No exception thrown");
- } catch (e) {
- Expect.isTrue(e is ArgumentError);
- }
- testFailingList(d, false);
- Expect.throws(() => d.listSync(recursive: true),
- (e) => e is ArgumentError);
- d = new Directory(".");
+ Directory d = new Directory(".");
testFailingList(d, 1);
Expect.throws(() => d.listSync(recursive: 1),
(e) => e is ArgumentError);
diff --git a/tests/standalone/io/http_headers_test.dart b/tests/standalone/io/http_headers_test.dart
index 845f6f6..4b9b7a7 100644
--- a/tests/standalone/io/http_headers_test.dart
+++ b/tests/standalone/io/http_headers_test.dart
@@ -251,6 +251,8 @@
Expect.equals("", contentType.primaryType);
Expect.equals("", contentType.subType);
Expect.equals("/", contentType.value);
+ Expect.throws(() => contentType.parameters["xxx"] = "yyy",
+ (e) => e is UnsupportedError);
contentType = ContentType.parse("text/html");
check(contentType, "text", "html");
@@ -258,6 +260,8 @@
contentType = new ContentType("text", "html", charset: "utf-8");
check(contentType, "text", "html", {"charset": "utf-8"});
Expect.equals("text/html; charset=utf-8", contentType.toString());
+ Expect.throws(() => contentType.parameters["xxx"] = "yyy",
+ (e) => e is UnsupportedError);
contentType = new ContentType("text",
"html",
@@ -267,6 +271,8 @@
bool expectedToString = (s == "text/html; charset=utf-8; xxx=yyy" ||
s == "text/html; xxx=yyy; charset=utf-8");
Expect.isTrue(expectedToString);
+ Expect.throws(() => contentType.parameters["xxx"] = "yyy",
+ (e) => e is UnsupportedError);
contentType = new ContentType("text",
"html",
diff --git a/tests/standalone/io/pkcert/myauthority.pem b/tests/standalone/io/pkcert/myauthority.pem
new file mode 100644
index 0000000..3aebea4
--- /dev/null
+++ b/tests/standalone/io/pkcert/myauthority.pem
@@ -0,0 +1,11 @@
+-----BEGIN CERTIFICATE-----
+MIIBpDCCAQ2gAwIBAgIFAJq4IS0wDQYJKoZIhvcNAQEFBQAwFjEUMBIGA1UEAxML
+bXlhdXRob3JpdHkwHhcNMTMwMjE1MTA0MzA5WhcNMTgwMjE1MTA0MzA5WjAWMRQw
+EgYDVQQDEwtteWF1dGhvcml0eTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA
+tnrkyrXF1SEUeOdIiULWs0dOEUlX6t73UDVbbTorF6R66fkjkEK3vW9ekZFUWq5+
+HVku4LUViJR140+F+CzUYtN73Ur28GqLa6LY4XtzHfPSfgecgayI1mEU+0f/2l8B
+4RiE9V8mW9RqPM6Lb69QrwXSYdzStl6ltuLJhgPGqAMCAwEAATANBgkqhkiG9w0B
+AQUFAAOBgQBdBUQTUR5oIRdqBGR87qW7caLAuPoVmzikOrSBNoyamVF0lwFFxgNw
+sj5VWdMn0SJhXd3EUMVlHr+4B/c3jUy1PlvBQGURn2cp5c4tj3FMOqkemuA0ywOF
+gbt2lqi7/RW4bHITqfPi7CDzE36n25vXc64Ylk7vEi3hUfjYfIqNcA==
+-----END CERTIFICATE-----
diff --git a/tests/standalone/53bit_overflow_literal_test.dart b/tests/standalone/javascript_int_overflow_literal_test.dart
similarity index 71%
rename from tests/standalone/53bit_overflow_literal_test.dart
rename to tests/standalone/javascript_int_overflow_literal_test.dart
index 1062af0..36c7b5b 100644
--- a/tests/standalone/53bit_overflow_literal_test.dart
+++ b/tests/standalone/javascript_int_overflow_literal_test.dart
@@ -8,11 +8,11 @@
import "package:expect/expect.dart";
int literals() {
- var okay_literal = 0xFFFFFFFFFFFFF;
- var too_big_literal = 0x1FFFFFFFFFFFFF; /// 01: compile-time error
+ var okay_literal = 0x1FFFFFFFFFFFFF;
+ var too_big_literal = 0x20000000000000; /// 01: compile-time error
return okay_literal;
}
main() {
- Expect.equals(0xFFFFFFFFFFFFF, literals());
+ Expect.equals(0x1FFFFFFFFFFFFF, literals());
}
diff --git a/tests/standalone/javascript_int_overflow_test.dart b/tests/standalone/javascript_int_overflow_test.dart
new file mode 100644
index 0000000..6e1eb9b
--- /dev/null
+++ b/tests/standalone/javascript_int_overflow_test.dart
@@ -0,0 +1,119 @@
+// Copyright (c) 2013, 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.
+
+// VMOptions=--throw_on_javascript_int_overflow --optimization_counter_threshold=10
+
+
+import "package:expect/expect.dart";
+import 'dart:typed_data';
+
+
+double dti_arg;
+int double_to_int() {
+ return dti_arg.toInt();
+}
+
+
+int ia_arg1;
+int ia_arg2;
+int integer_add() {
+ return ia_arg1 + ia_arg2;
+}
+
+
+int is_arg;
+int integer_shift() {
+ return is_arg << 1;
+}
+
+
+int max_add_throws() {
+ return 0x1FFFFFFFFFFFFF + 1;
+}
+
+
+int min_sub_throws() {
+ return -0x1FFFFFFFFFFFFF - 1;
+}
+
+
+int n_arg;
+int negate() {
+ return -n_arg;
+}
+
+
+int max_literal() {
+ return 0x1FFFFFFFFFFFFF;
+}
+
+
+int min_literal() {
+ var min_literal = -0x1FFFFFFFFFFFFF;
+ return min_literal;
+}
+
+// We don't test for the _JavascriptIntegerOverflowError since it's not visible.
+// It should not be visible since it doesn't exist on dart2js.
+bool isJavascriptIntError(e) =>
+ e is Error && "$e".startsWith("Javascript Integer Overflow:");
+
+main() {
+ Expect.equals(0x1FFFFFFFFFFFFF, max_literal());
+ Expect.equals(-0x1FFFFFFFFFFFFF, min_literal());
+
+ // Run the tests once before optimizations.
+ dti_arg = 1.9e16;
+ Expect.throws(double_to_int, isJavascriptIntError);
+
+ ia_arg1 = (1 << 52);
+ ia_arg2 = (1 << 52);
+ Expect.throws(integer_add, isJavascriptIntError);
+
+ n_arg = -0x1FFFFFFFFFFFFF;
+ Expect.equals(0x1FFFFFFFFFFFFF, negate());
+
+ is_arg = (1 << 52);
+ Expect.throws(integer_shift, isJavascriptIntError);
+
+ Expect.throws(max_add_throws, isJavascriptIntError);
+ Expect.throws(min_sub_throws, isJavascriptIntError);
+
+ for (int i = 0; i < 20; i++) {
+ dti_arg = i.toDouble();
+ // Expect.throws calls through the closure, so we have to here, too.
+ var f = double_to_int;
+ Expect.equals(i, f());
+
+ ia_arg1 = i;
+ ia_arg2 = i;
+ f = integer_add;
+ Expect.equals(i + i, f());
+
+ n_arg = i;
+ f = negate;
+ Expect.equals(-i, f());
+
+ is_arg = i;
+ f = integer_shift;
+ Expect.equals(i << 1, f());
+ }
+
+ // The optimized functions should now deoptimize and throw the error.
+ dti_arg = 1.9e16;
+ Expect.throws(double_to_int, isJavascriptIntError);
+
+ ia_arg1 = (1 << 52);
+ ia_arg2 = (1 << 52);
+ Expect.throws(integer_add, isJavascriptIntError);
+
+ n_arg = -0x1FFFFFFFFFFFFF;
+ Expect.equals(0x1FFFFFFFFFFFFF, negate());
+
+ is_arg = (1 << 52);
+ Expect.throws(integer_shift, isJavascriptIntError);
+
+ Expect.throws(max_add_throws, isJavascriptIntError);
+ Expect.throws(min_sub_throws, isJavascriptIntError);
+}
diff --git a/tests/standalone/standalone.status b/tests/standalone/standalone.status
index 6622e10..abac10e 100644
--- a/tests/standalone/standalone.status
+++ b/tests/standalone/standalone.status
@@ -24,6 +24,9 @@
io/file_fuzz_test: Skip
io/directory_fuzz_test: Skip
+[ $runtime == vm && $system == windows ]
+vmservice/multiple_isolate_list_test: Fail, Pass # http://dartbug.com/12124
+
[ $runtime == vm && $system == macos ]
# This test fails with "Too many open files" on the Mac OS buildbot.
# This is expected as MacOS by default runs with a very low number
@@ -49,12 +52,10 @@
coverage_test: Skip
http_launch_test: Skip
vmservice/*: Skip # Do not run standalone vm service tests in browser.
-53bit_overflow_literal_test: fail # Issue 12044
-53bit_overflow_test: fail # Issue 12044
[ $compiler == dartanalyzer ]
-53bit_overflow_literal_test/01: fail, ok
+javascript_int_overflow_literal_test/01: fail, ok
# test issue https://code.google.com/p/dart/issues/detail?id=11518
io/file_constructor_test: fail
@@ -75,7 +76,7 @@
package/package_isolate_test: fail
[ $compiler == dart2analyzer ]
-53bit_overflow_literal_test/01: fail, ok
+javascript_int_overflow_literal_test/01: fail, ok
package/package_isolate_test: fail # issue 11647
# test issue https://code.google.com/p/dart/issues/detail?id=11518
@@ -115,8 +116,8 @@
pow_test: Skip # Precision > 53 bits.
double_smi_comparison_test: Skip # Precision > 53 bits.
http_launch_test: Skip
-53bit_overflow_test: Skip
-53bit_overflow_literal_test: Skip
+javascript_int_overflow_test: Skip
+javascript_int_overflow_literal_test: Skip
oom_error_stacktrace_test: Fail, OK # (OOM on JS may produce a stacktrace).
vmservice/*: Skip # Do not run standalone vm service tests with dart2js.
@@ -156,6 +157,8 @@
[ $arch == simmips ]
io/file_fuzz_test: Pass, Timeout
+io/web_socket_test: Pass, Slow
+io/http_server_response_test: Pass, Slow
out_of_memory_test: Skip # passes on Mac, crashes on Linux
oom_error_stacktrace_test: Skip # Fails on Linux
io/web_socket_ping_test: Skip # TODO(ajohnsen): Timeout issue
diff --git a/tools/VERSION b/tools/VERSION
index 0e05268..5c1426a 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -1,4 +1,4 @@
MAJOR 0
MINOR 6
-BUILD 13
+BUILD 14
PATCH 0
diff --git a/tools/dom/scripts/generator.py b/tools/dom/scripts/generator.py
index f966029..9ec3351 100644
--- a/tools/dom/scripts/generator.py
+++ b/tools/dom/scripts/generator.py
@@ -136,6 +136,8 @@
'TransitionEvent': 'TransitionEvent,WebKitTransitionEvent',
+ 'WebGLLoseContext': 'WebGLLoseContext,WebGLExtensionLoseContext',
+
'WebKitCSSKeyframeRule':
'CSSKeyframeRule,MozCSSKeyframeRule,WebKitCSSKeyframeRule',
diff --git a/tools/dom/scripts/htmlrenamer.py b/tools/dom/scripts/htmlrenamer.py
index 89753be..a8ca1a2 100644
--- a/tools/dom/scripts/htmlrenamer.py
+++ b/tools/dom/scripts/htmlrenamer.py
@@ -717,9 +717,10 @@
# Manual dart: library name lookup.
_library_names = monitored.Dict('htmlrenamer._library_names', {
- 'Window': 'html',
+ 'ANGLEInstancedArrays': 'web_gl',
'Database': 'web_sql',
'Navigator': 'html',
+ 'Window': 'html',
'WorkerContext': 'html',
})
diff --git a/tools/dom/scripts/systemnative.py b/tools/dom/scripts/systemnative.py
index 1c5930a..91dd180 100644
--- a/tools/dom/scripts/systemnative.py
+++ b/tools/dom/scripts/systemnative.py
@@ -478,6 +478,8 @@
dart_element_type = self._DartType(element_type)
if self._HasNativeIndexGetter():
self._EmitNativeIndexGetter(dart_element_type)
+ elif self._HasExplicitIndexedGetter():
+ self._EmitExplicitIndexedGetter(dart_element_type)
else:
self._members_emitter.Emit(
'\n'
@@ -526,6 +528,23 @@
self._GenerateNativeBinding('numericIndexGetter', 2, dart_declaration,
'Callback', True)
+ def _HasExplicitIndexedGetter(self):
+ return any(op.id == 'getItem' for op in self._interface.operations)
+
+ def _EmitExplicitIndexedGetter(self, dart_element_type):
+ if any(op.id == 'getItem' for op in self._interface.operations):
+ indexed_getter = 'getItem'
+
+ self._members_emitter.Emit(
+ '\n'
+ ' $TYPE operator[](int index) {\n'
+ ' if (index < 0 || index >= length)\n'
+ ' throw new RangeError.range(index, 0, length);\n'
+ ' return $INDEXED_GETTER(index);\n'
+ ' }\n',
+ TYPE=dart_element_type,
+ INDEXED_GETTER=indexed_getter)
+
def _HasNativeIndexSetter(self):
return 'CustomIndexedSetter' in self._interface.ext_attrs
@@ -899,12 +918,18 @@
value_expression = function_call
# Generate to Dart conversion of C++ value.
- to_dart_conversion = return_type_info.to_dart_conversion(value_expression, self._interface.id, ext_attrs)
+ if return_type_info.dart_type() == 'bool':
+ set_return_value = 'Dart_SetBooleanReturnValue(args, %s)' % (value_expression)
+ elif return_type_info.dart_type() == 'int':
+ set_return_value = 'Dart_SetIntegerReturnValue(args, %s)' % (value_expression)
+ elif return_type_info.dart_type() == 'double':
+ set_return_value = 'Dart_SetDoubleReturnValue(args, %s)' % (value_expression)
+ else:
+ to_dart_conversion = return_type_info.to_dart_conversion(value_expression, self._interface.id, ext_attrs)
+ set_return_value = 'Dart_SetReturnValue(args, %s)' % (to_dart_conversion)
invocation_emitter.Emit(
- ' Dart_Handle returnValue = $TO_DART_CONVERSION;\n'
- ' if (returnValue)\n'
- ' Dart_SetReturnValue(args, returnValue);\n',
- TO_DART_CONVERSION=to_dart_conversion)
+ ' $RETURN_VALUE;\n',
+ RETURN_VALUE=set_return_value)
def _GenerateNativeBinding(self, idl_name, argument_count, dart_declaration,
native_suffix, is_custom, emit_metadata=True):
diff --git a/tools/dom/templates/html/impl/impl_CSSStyleDeclaration.darttemplate b/tools/dom/templates/html/impl/impl_CSSStyleDeclaration.darttemplate
index 984f10d..c0120c2 100644
--- a/tools/dom/templates/html/impl/impl_CSSStyleDeclaration.darttemplate
+++ b/tools/dom/templates/html/impl/impl_CSSStyleDeclaration.darttemplate
@@ -4,7 +4,8 @@
part of $LIBRARYNAME;
-$(ANNOTATIONS)$(CLASS_MODIFIERS)class $CLASSNAME$EXTENDS$IMPLEMENTS$NATIVESPEC {
+$(ANNOTATIONS)$(CLASS_MODIFIERS) class $CLASSNAME $EXTENDS with
+ $(CLASSNAME)Base $IMPLEMENTS$NATIVESPEC {
factory $CLASSNAME() => new CssStyleDeclaration.css('');
factory $CLASSNAME.css(String css) {
@@ -12,9 +13,7 @@
style.cssText = css;
return style;
}
-
-$!MEMBERS
-
+
String getPropertyValue(String propertyName) {
var propValue = _getPropertyValue(propertyName);
return propValue != null ? propValue : '';
@@ -35,7 +34,7 @@
}
} catch (e) {}
}
-
+
/**
* Checks to see if CSS Transitions are supported.
*/
@@ -47,11 +46,6 @@
return JS('bool', '# in document.body.style', propertyName);
}
$else
- /**
- * Checks to see if CSS Transitions are supported.
- */
- static bool get supportsTransitions => true;
-
@DomName('CSSStyleDeclaration.setProperty')
void setProperty(String propertyName, String value, [String priority]) {
if (priority == null) {
@@ -59,7 +53,42 @@
}
_setProperty(propertyName, value, priority);
}
+
+ /**
+ * Checks to see if CSS Transitions are supported.
+ */
+ static bool get supportsTransitions => true;
$endif
+$!MEMBERS
+}
+
+class _CssStyleDeclarationSet extends Object with CssStyleDeclarationBase {
+ final Iterable<Element> _elementIterable;
+ Iterable<CssStyleDeclaration> _elementCssStyleDeclarationSetIterable;
+
+ _CssStyleDeclarationSet(this._elementIterable) {
+ _elementCssStyleDeclarationSetIterable = new List.from(
+ _elementIterable).map((e) => e.style);
+ }
+
+ String getPropertyValue(String propertyName) =>
+ _elementCssStyleDeclarationSetIterable.first.getPropertyValue(
+ propertyName);
+
+ void setProperty(String propertyName, String value, [String priority]) {
+ _elementCssStyleDeclarationSetIterable.forEach((e) =>
+ e.setProperty(propertyName, value, priority));
+ }
+ // Important note: CssStyleDeclarationSet does NOT implement every method
+ // available in CssStyleDeclaration. Some of the methods don't make so much
+ // sense in terms of having a resonable value to return when you're
+ // considering a list of Elements. You will need to manually add any of the
+ // items in the MEMBERS set if you want that functionality.
+}
+
+abstract class CssStyleDeclarationBase {
+ String getPropertyValue(String propertyName);
+ void setProperty(String propertyName, String value, [String priority]);
// TODO(jacobr): generate this list of properties using the existing script.
/** Gets the value of "align-content" */
diff --git a/tools/dom/templates/html/impl/impl_Element.darttemplate b/tools/dom/templates/html/impl/impl_Element.darttemplate
index 29533d8..8cfb668 100644
--- a/tools/dom/templates/html/impl/impl_Element.darttemplate
+++ b/tools/dom/templates/html/impl/impl_Element.darttemplate
@@ -157,7 +157,7 @@
/**
* An immutable list containing HTML elements. This list contains some
- * additional methods when compared to regular lists for ease of CSS
+ * additional methods when compared to regular lists for ease of CSS
* manipulation on a group of elements.
*/
abstract class ElementList<T extends Element> extends ListBase<T> {
@@ -176,28 +176,40 @@
/** Replace the classes with `value` for every element in this list. */
set classes(Iterable<String> value);
- /**
+ /**
+ * Access the union of all [CssStyleDeclaration]s that are associated with an
+ * [ElementList].
+ *
+ * Grouping the style objects all together provides easy editing of specific
+ * properties of a collection of elements. Setting a specific property value
+ * will set that property in all [Element]s in the [ElementList]. Getting a
+ * specific property value will return the value of the property of the first
+ * element in the [ElementList].
+ */
+ CssStyleDeclarationBase get style;
+
+ /**
* Access dimensions and position of the Elements in this list.
- *
+ *
* Setting the height or width properties will set the height or width
- * property for all elements in the list. This returns a rectangle with the
+ * property for all elements in the list. This returns a rectangle with the
* dimenions actually available for content
- * in this element, in pixels, regardless of this element's box-sizing
+ * in this element, in pixels, regardless of this element's box-sizing
* property. Getting the height or width returns the height or width of the
- * first Element in this list.
+ * first Element in this list.
*
* Unlike [getBoundingClientRect], the dimensions of this rectangle
* will return the same numerical height if the element is hidden or not.
*/
@Experimental()
CssRect get contentEdge;
-
+
/**
* Access dimensions and position of the first Element's content + padding box
* in this list.
- *
+ *
* This returns a rectangle with the dimenions actually available for content
- * in this element, in pixels, regardless of this element's box-sizing
+ * in this element, in pixels, regardless of this element's box-sizing
* property. Unlike [getBoundingClientRect], the dimensions of this rectangle
* will return the same numerical height if the element is hidden or not. This
* can be used to retrieve jQuery's `innerHeight` value for an element. This
@@ -210,9 +222,9 @@
/**
* Access dimensions and position of the first Element's content + padding +
* border box in this list.
- *
+ *
* This returns a rectangle with the dimenions actually available for content
- * in this element, in pixels, regardless of this element's box-sizing
+ * in this element, in pixels, regardless of this element's box-sizing
* property. Unlike [getBoundingClientRect], the dimensions of this rectangle
* will return the same numerical height if the element is hidden or not. This
* can be used to retrieve jQuery's `outerHeight` value for an element.
@@ -223,9 +235,9 @@
/**
* Access dimensions and position of the first Element's content + padding +
* border + margin box in this list.
- *
+ *
* This returns a rectangle with the dimenions actually available for content
- * in this element, in pixels, regardless of this element's box-sizing
+ * in this element, in pixels, regardless of this element's box-sizing
* property. Unlike [getBoundingClientRect], the dimensions of this rectangle
* will return the same numerical height if the element is hidden or not. This
* can be used to retrieve jQuery's `outerHeight` value for an element.
@@ -271,12 +283,15 @@
CssClassSet get classes => new _MultiElementCssClassSet(_elementList);
+ CssStyleDeclarationBase get style =>
+ new _CssStyleDeclarationSet(_elementList);
+
void set classes(Iterable<String> value) {
_elementList.forEach((e) => e.classes = value);
}
CssRect get contentEdge => new _ContentCssListRect(_elementList);
-
+
CssRect get paddingEdge => _elementList.first.paddingEdge;
CssRect get borderEdge => _elementList.first.borderEdge;
@@ -937,13 +952,13 @@
}
/**
- * Creates an instance of the template, using the provided model and binding
- * delegate.
+ * Creates an instance of the template, using the provided model and optional
+ * binding delegate.
*
* This is only supported if [isTemplate] is true.
*/
@Experimental()
- DocumentFragment createInstance(model, BindingDelegate delegate) {
+ DocumentFragment createInstance(model, [BindingDelegate delegate]) {
_ensureTemplate();
return TemplateElement.mdvPackage(this).createInstance(model, delegate);
}
@@ -1019,35 +1034,35 @@
/**
* Access this element's content position.
- *
+ *
* This returns a rectangle with the dimenions actually available for content
- * in this element, in pixels, regardless of this element's box-sizing
+ * in this element, in pixels, regardless of this element's box-sizing
* property. Unlike [getBoundingClientRect], the dimensions of this rectangle
* will return the same numerical height if the element is hidden or not.
- *
+ *
* _Important_ _note_: use of this method _will_ perform CSS calculations that
- * can trigger a browser reflow. Therefore, use of this property _during_ an
- * animation frame is discouraged. See also:
+ * can trigger a browser reflow. Therefore, use of this property _during_ an
+ * animation frame is discouraged. See also:
* [Browser Reflow](https://developers.google.com/speed/articles/reflow)
*/
@Experimental()
CssRect get contentEdge => new _ContentCssRect(this);
-
+
/**
* Access the dimensions and position of this element's content + padding box.
- *
+ *
* This returns a rectangle with the dimenions actually available for content
- * in this element, in pixels, regardless of this element's box-sizing
+ * in this element, in pixels, regardless of this element's box-sizing
* property. Unlike [getBoundingClientRect], the dimensions of this rectangle
* will return the same numerical height if the element is hidden or not. This
* can be used to retrieve jQuery's
- * [innerHeight](http://api.jquery.com/innerHeight/) value for an element.
+ * [innerHeight](http://api.jquery.com/innerHeight/) value for an element.
* This is also a rectangle equalling the dimensions of clientHeight and
* clientWidth.
- *
+ *
* _Important_ _note_: use of this method _will_ perform CSS calculations that
- * can trigger a browser reflow. Therefore, use of this property _during_ an
- * animation frame is discouraged. See also:
+ * can trigger a browser reflow. Therefore, use of this property _during_ an
+ * animation frame is discouraged. See also:
* [Browser Reflow](https://developers.google.com/speed/articles/reflow)
*/
@Experimental()
@@ -1056,17 +1071,17 @@
/**
* Access the dimensions and position of this element's content + padding +
* border box.
- *
+ *
* This returns a rectangle with the dimenions actually available for content
- * in this element, in pixels, regardless of this element's box-sizing
+ * in this element, in pixels, regardless of this element's box-sizing
* property. Unlike [getBoundingClientRect], the dimensions of this rectangle
* will return the same numerical height if the element is hidden or not. This
* can be used to retrieve jQuery's
* [outerHeight](http://api.jquery.com/outerHeight/) value for an element.
- *
- * _Important_ _note_: use of this method _will_ perform CSS calculations that
- * can trigger a browser reflow. Therefore, use of this property _during_ an
- * animation frame is discouraged. See also:
+ *
+ * _Important_ _note_: use of this method _will_ perform CSS calculations that
+ * can trigger a browser reflow. Therefore, use of this property _during_ an
+ * animation frame is discouraged. See also:
* [Browser Reflow](https://developers.google.com/speed/articles/reflow)
*/
@Experimental()
@@ -1075,38 +1090,38 @@
/**
* Access the dimensions and position of this element's content + padding +
* border + margin box.
- *
+ *
* This returns a rectangle with the dimenions actually available for content
- * in this element, in pixels, regardless of this element's box-sizing
+ * in this element, in pixels, regardless of this element's box-sizing
* property. Unlike [getBoundingClientRect], the dimensions of this rectangle
* will return the same numerical height if the element is hidden or not. This
* can be used to retrieve jQuery's
* [outerHeight](http://api.jquery.com/outerHeight/) value for an element.
- *
+ *
* _Important_ _note_: use of this method will perform CSS calculations that
- * can trigger a browser reflow. Therefore, use of this property _during_ an
- * animation frame is discouraged. See also:
+ * can trigger a browser reflow. Therefore, use of this property _during_ an
+ * animation frame is discouraged. See also:
* [Browser Reflow](https://developers.google.com/speed/articles/reflow)
*/
@Experimental()
CssRect get marginEdge => new _MarginCssRect(this);
- /**
- * Provides the coordinates of the element relative to the top of the
- * document.
+ /**
+ * Provides the coordinates of the element relative to the top of the
+ * document.
*
- * This method is the Dart equivalent to jQuery's
+ * This method is the Dart equivalent to jQuery's
* [offset](http://api.jquery.com/offset/) method.
*/
Point get documentOffset => offsetTo(document.documentElement);
- /**
+ /**
* Provides the offset of this element's [borderEdge] relative to the
* specified [parent].
- *
+ *
* This is the Dart equivalent of jQuery's
* [position](http://api.jquery.com/position/) method. Unlike jQuery's
- * position, however, [parent] can be any parent element of `this`,
+ * position, however, [parent] can be any parent element of `this`,
* rather than only `this`'s immediate [offsetParent]. If the specified
* element is _not_ an offset parent or transitive offset parent to this
* element, an [ArgumentError] is thrown.
@@ -1117,7 +1132,7 @@
static Point _offsetToHelper(Element current, Element parent) {
// We're hopping from _offsetParent_ to offsetParent (not just parent), so
- // offsetParent, "tops out" at BODY. But people could conceivably pass in
+ // offsetParent, "tops out" at BODY. But people could conceivably pass in
// the document.documentElement and I want it to return an absolute offset,
// so we have the special case checking for HTML.
bool foundAsParent = identical(current, parent) || parent.tagName == 'HTML';
@@ -1125,7 +1140,7 @@
if (foundAsParent) return new Point(0, 0);
throw new ArgumentError("Specified element is not a transitive offset "
"parent of this element.");
- }
+ }
Element parentOffset = current.offsetParent;
Point p = Element._offsetToHelper(parentOffset, parent);
return new Point(p.x + current.offsetLeft, p.y + current.offsetTop);