Version 0.8.1.0 .
svn merge -r 28200:28280 https://dart.googlecode.com/svn/branches/bleeding_edge trunk
git-svn-id: http://dart.googlecode.com/svn/trunk@28283 260f80e4-7a28-3924-810f-c04153c831b5
diff --git a/pkg/analyzer_experimental/lib/src/generated/java_core.dart b/pkg/analyzer_experimental/lib/src/generated/java_core.dart
index be03c50..c136b7a 100644
--- a/pkg/analyzer_experimental/lib/src/generated/java_core.dart
+++ b/pkg/analyzer_experimental/lib/src/generated/java_core.dart
@@ -376,6 +376,10 @@
elements.sort(compare);
}
+ void shuffle() {
+ elements.shuffle();
+ }
+
int indexOf(E element, [int start = 0]) {
return elements.indexOf(element, start);
}
@@ -583,4 +587,4 @@
String group(int i) => _match[i];
int start() => _match.start;
int end() => _match.end;
-}
\ No newline at end of file
+}
diff --git a/pkg/analyzer_experimental/test/utils.dart b/pkg/analyzer_experimental/test/utils.dart
index 637fe0c..df22ff8 100644
--- a/pkg/analyzer_experimental/test/utils.dart
+++ b/pkg/analyzer_experimental/test/utils.dart
@@ -38,7 +38,8 @@
///
/// Returns the return value of [fn].
dynamic withTempDir(fn(String path)) {
- var tempDir = new Directory('').createTempSync().path;
+ var tempDir =
+ Directory.systemTemp.createTempSync('analyzer_experimental_').path;
try {
return fn(tempDir);
} finally {
diff --git a/pkg/barback/lib/src/transform_logger.dart b/pkg/barback/lib/src/transform_logger.dart
index 131be29..e68573a 100644
--- a/pkg/barback/lib/src/transform_logger.dart
+++ b/pkg/barback/lib/src/transform_logger.dart
@@ -14,6 +14,14 @@
TransformLogger(this._shouldPrint);
+ /// Logs an informative message.
+ ///
+ /// If present, [span] indicates the location in the input asset that caused
+ /// the message.
+ void info(String message, [Span span]) {
+ _printMessage('info', message, span);
+ }
+
/// Logs a warning message.
///
/// If present, [span] indicates the location in the input asset that caused
@@ -34,7 +42,7 @@
// TODO(sigmund,rnystrom): do something better than printing.
_printMessage(String prefix, String message, Span span) {
if (!_shouldPrint) return;
- print(span == null ? '$prefix $message'
+ print(span == null ? '$prefix: $message'
: '$prefix ${span.getLocationMessage(message)}');
}
}
diff --git a/pkg/barback/test/asset_test.dart b/pkg/barback/test/asset_test.dart
index 5563ebf..74f459e 100644
--- a/pkg/barback/test/asset_test.dart
+++ b/pkg/barback/test/asset_test.dart
@@ -27,7 +27,7 @@
setUp(() {
// Create a temp file we can use for assets.
- tempDir = new Directory("").createTempSync();
+ tempDir = Directory.systemTemp.createTempSync('barback_asset_test_');
binaryFilePath = pathos.join(tempDir.path, "file.bin");
new File(binaryFilePath).writeAsBytesSync(binaryContents);
diff --git a/pkg/custom_element/lib/custom_element.dart b/pkg/custom_element/lib/custom_element.dart
index 19824cf..a91ff69 100644
--- a/pkg/custom_element/lib/custom_element.dart
+++ b/pkg/custom_element/lib/custom_element.dart
@@ -481,7 +481,7 @@
@deprecated
int get clientWidth => client.width;
- Rect get client => host.client;
+ Rectangle get client => host.client;
@deprecated
int get offsetHeight => offset.height;
@@ -495,7 +495,7 @@
@deprecated
int get offsetWidth => offset.width;
- Rect get offset => host.offset;
+ Rectangle get offset => host.offset;
int get scrollHeight => host.scrollHeight;
@@ -509,9 +509,9 @@
int get scrollWidth => host.scrollWidth;
- Rect getBoundingClientRect() => host.getBoundingClientRect();
+ Rectangle getBoundingClientRect() => host.getBoundingClientRect();
- List<Rect> getClientRects() => host.getClientRects();
+ List<Rectangle> getClientRects() => host.getClientRects();
List<Node> getElementsByClassName(String name) =>
host.getElementsByClassName(name);
diff --git a/pkg/docgen/test/single_library_test.dart b/pkg/docgen/test/single_library_test.dart
index dd4044e..5f9949e 100644
--- a/pkg/docgen/test/single_library_test.dart
+++ b/pkg/docgen/test/single_library_test.dart
@@ -1,36 +1,30 @@
library single_library_test;
-import 'dart:io';
+import 'dart:io';
import 'package:path/path.dart' as path;
import 'package:unittest/unittest.dart';
import '../lib/docgen.dart';
-main() {
- group('Generate docs for', () {
- test('one simple file.', () {
- var temporaryDir = Directory.createSystemTempSync('single_library_');
- var fileName = path.join(temporaryDir.path, 'temp.dart');
- var file = new File(fileName);
- file.writeAsStringSync('''
+const String DART_LIBRARY = '''
library test;
/**
* Doc comment for class [A].
- *
+ *
* Multiline Test
*/
/*
* Normal comment for class A.
*/
class A {
-
+
int _someNumber;
-
+
A() {
_someNumber = 12;
}
-
+
/**
* Test for linking to parameter [A]
*/
@@ -38,30 +32,37 @@
print(A);
}
}
-
+
main() {
A a = new A();
a.doThis(5);
}
- ''');
-
+''';
+
+main() {
+ group('Generate docs for', () {
+ test('one simple file.', () {
+ var temporaryDir = Directory.systemTemp.createTempSync('single_library_');
+ var fileName = path.join(temporaryDir.path, 'temp.dart');
+ var file = new File(fileName);
+ file.writeAsStringSync(DART_LIBRARY);
getMirrorSystem([fileName])
.then(expectAsync1((mirrorSystem) {
- var testLibraryUri = new Uri(scheme: 'file',
+ var testLibraryUri = new Uri(scheme: 'file',
path: path.absolute(fileName));
var library = generateLibrary(mirrorSystem.libraries[testLibraryUri]);
expect(library is Library, isTrue);
-
+
var classTypes = library.classes;
expect(classTypes is ClassGroup, isTrue);
-
+
var classes = [];
classes.addAll(classTypes.classes.values);
classes.addAll(classTypes.errors.values);
expect(classes.every((e) => e is Class), isTrue);
-
+
expect(classTypes.typedefs.values.every((e) => e is Typedef), isTrue);
-
+
var classMethodTypes = [];
classes.forEach((e) {
classMethodTypes.add(e.methods);
@@ -78,16 +79,16 @@
classMethods.addAll(e.regularMethods.values);
});
expect(classMethods.every((e) => e is Method), isTrue);
-
+
var methodParameters = [];
- classMethods.forEach((e) {
+ classMethods.forEach((e) {
methodParameters.addAll(e.parameters.values);
});
expect(methodParameters.every((e) => e is Parameter), isTrue);
-
+
var functionTypes = library.functions;
expect(functionTypes is MethodGroup, isTrue);
-
+
var functions = [];
functions.addAll(functionTypes.setters.values);
functions.addAll(functionTypes.getters.values);
@@ -95,35 +96,35 @@
functions.addAll(functionTypes.operators.values);
functions.addAll(functionTypes.regularMethods.values);
expect(functions.every((e) => e is Method), isTrue);
-
+
var functionParameters = [];
functions.forEach((e) {
- functionParameters.addAll(e.parameters.values);
+ functionParameters.addAll(e.parameters.values);
});
expect(functionParameters.every((e) => e is Parameter), isTrue);
-
+
var variables = library.variables.values;
expect(variables.every((e) => e is Variable), isTrue);
-
- /// Testing fixReference
+
+ /// Testing fixReference
// Testing Doc comment for class [A].
var libraryMirror = mirrorSystem.libraries[testLibraryUri];
var classMirror = libraryMirror.classes.values.first;
- var classDocComment = fixReference('A', libraryMirror,
+ var classDocComment = fixReference('A', libraryMirror,
classMirror, null).children.first.text;
expect(classDocComment == 'test.A', isTrue);
-
+
// Test for linking to parameter [A]
var methodMirror = classMirror.methods['doThis'];
var methodParameterDocComment = fixReference('A', libraryMirror,
classMirror, methodMirror).children.first.text;
expect(methodParameterDocComment == 'test.A.doThis#A', isTrue);
-
+
// Testing trying to refer to doThis function
- var methodDocComment = fixReference('doThis', libraryMirror,
+ var methodDocComment = fixReference('doThis', libraryMirror,
classMirror, methodMirror).children.first.text;
expect(methodDocComment == 'test.A.doThis', isTrue);
-
+
// Testing something with no reference
var libraryDocComment = fixReference('foobar', libraryMirror,
classMirror, methodMirror).children.first.text;
diff --git a/pkg/http/test/multipart_test.dart b/pkg/http/test/multipart_test.dart
index c42b810..7467d5f 100644
--- a/pkg/http/test/multipart_test.dart
+++ b/pkg/http/test/multipart_test.dart
@@ -216,7 +216,7 @@
group('in a temp directory', () {
var tempDir;
setUp(() {
- tempDir = new Directory('').createTempSync();
+ tempDir = Directory.systemTemp.createTempSync('http_test_');
});
tearDown(() => tempDir.deleteSync(recursive: true));
diff --git a/pkg/http_server/test/virtual_directory_test.dart b/pkg/http_server/test/virtual_directory_test.dart
index 4b59f2c..9d38e68 100644
--- a/pkg/http_server/test/virtual_directory_test.dart
+++ b/pkg/http_server/test/virtual_directory_test.dart
@@ -16,7 +16,7 @@
group('serve-root', () {
test('dir-exists', () {
expect(HttpServer.bind('localhost', 0).then((server) {
- var dir = new Directory('').createTempSync();
+ var dir = Directory.systemTemp.createTempSync('http_server_virtual_');
var virDir = new VirtualDirectory(dir.path);
virDir.serve(server);
@@ -31,7 +31,7 @@
test('dir-not-exists', () {
expect(HttpServer.bind('localhost', 0).then((server) {
- var dir = new Directory('').createTempSync();
+ var dir = Directory.systemTemp.createTempSync('http_server_virtual_');
dir.deleteSync();
var virDir = new VirtualDirectory(dir.path);
@@ -49,7 +49,7 @@
group('top-level', () {
test('file-exists', () {
expect(HttpServer.bind('localhost', 0).then((server) {
- var dir = new Directory('').createTempSync();
+ var dir = Directory.systemTemp.createTempSync('http_server_virtual_');
var file = new File('${dir.path}/file')..createSync();
var virDir = new VirtualDirectory(dir.path);
@@ -65,7 +65,7 @@
test('file-not-exists', () {
expect(HttpServer.bind('localhost', 0).then((server) {
- var dir = new Directory('').createTempSync();
+ var dir = Directory.systemTemp.createTempSync('http_server_virtual_');
var virDir = new VirtualDirectory(dir.path);
virDir.serve(server);
@@ -82,7 +82,7 @@
group('in-dir', () {
test('file-exists', () {
expect(HttpServer.bind('localhost', 0).then((server) {
- var dir = new Directory('').createTempSync();
+ var dir = Directory.systemTemp.createTempSync('http_server_virtual_');
var dir2 = new Directory('${dir.path}/dir')..createSync();
var file = new File('${dir2.path}/file')..createSync();
var virDir = new VirtualDirectory(dir.path);
@@ -99,7 +99,7 @@
test('file-not-exists', () {
expect(HttpServer.bind('localhost', 0).then((server) {
- var dir = new Directory('').createTempSync();
+ var dir = Directory.systemTemp.createTempSync('http_server_virtual_');
var dir2 = new Directory('${dir.path}/dir')..createSync();
var file = new File('${dir.path}/file')..createSync();
var virDir = new VirtualDirectory(dir.path);
@@ -120,7 +120,7 @@
group('top-level', () {
test('simple', () {
expect(HttpServer.bind('localhost', 0).then((server) {
- var dir = new Directory('').createTempSync();
+ var dir = Directory.systemTemp.createTempSync('http_server_virtual_');
var virDir = new VirtualDirectory(dir.path);
virDir.allowDirectoryListing = true;
@@ -136,7 +136,7 @@
test('files', () {
expect(HttpServer.bind('localhost', 0).then((server) {
- var dir = new Directory('').createTempSync();
+ var dir = Directory.systemTemp.createTempSync('http_server_virtual_');
var virDir = new VirtualDirectory(dir.path);
for (int i = 0; i < 10; i++) {
new File('${dir.path}/$i').createSync();
@@ -155,7 +155,7 @@
test('dirs', () {
expect(HttpServer.bind('localhost', 0).then((server) {
- var dir = new Directory('').createTempSync();
+ var dir = Directory.systemTemp.createTempSync('http_server_virtual_');
var virDir = new VirtualDirectory(dir.path);
for (int i = 0; i < 10; i++) {
new Directory('${dir.path}/$i').createSync();
@@ -175,7 +175,8 @@
if (!Platform.isWindows) {
test('recursive-link', () {
expect(HttpServer.bind('localhost', 0).then((server) {
- var dir = new Directory('').createTempSync();
+ var dir =
+ Directory.systemTemp.createTempSync('http_server_virtual_');
var link = new Link('${dir.path}/recursive')..createSync('.');
var virDir = new VirtualDirectory(dir.path);
virDir.allowDirectoryListing = true;
@@ -207,7 +208,7 @@
group('custom', () {
test('simple', () {
expect(HttpServer.bind('localhost', 0).then((server) {
- var dir = new Directory('').createTempSync();
+ var dir = Directory.systemTemp.createTempSync('http_server_virtual_');
var virDir = new VirtualDirectory(dir.path);
virDir.allowDirectoryListing = true;
virDir.setDirectoryHandler((dir2, request) {
@@ -234,7 +235,8 @@
group('follow-links', () {
test('dir-link', () {
expect(HttpServer.bind('localhost', 0).then((server) {
- var dir = new Directory('').createTempSync();
+ var dir =
+ Directory.systemTemp.createTempSync('http_server_virtual_');
var dir2 = new Directory('${dir.path}/dir2')..createSync();
var link = new Link('${dir.path}/dir3')..createSync('dir2');
var file = new File('${dir2.path}/file')..createSync();
@@ -253,7 +255,8 @@
test('root-link', () {
expect(HttpServer.bind('localhost', 0).then((server) {
- var dir = new Directory('').createTempSync();
+ var dir =
+ Directory.systemTemp.createTempSync('http_server_virtual_');
var link = new Link('${dir.path}/dir3')..createSync('.');
var file = new File('${dir.path}/file')..createSync();
var virDir = new VirtualDirectory(dir.path);
@@ -272,7 +275,8 @@
group('bad-links', () {
test('absolute-link', () {
expect(HttpServer.bind('localhost', 0).then((server) {
- var dir = new Directory('').createTempSync();
+ var dir =
+ Directory.systemTemp.createTempSync('http_server_virtual_');
var file = new File('${dir.path}/file')..createSync();
var link = new Link('${dir.path}/dir3')
..createSync('${dir.path}/file');
@@ -296,7 +300,8 @@
test('relative-parent-link', () {
expect(HttpServer.bind('localhost', 0).then((server) {
- var dir = new Directory('').createTempSync();
+ var dir =
+ Directory.systemTemp.createTempSync('http_server_virtual_');
var name = basename(dir.path);
var file = new File('${dir.path}/file')..createSync();
var link = new Link('${dir.path}/dir3')
@@ -324,7 +329,8 @@
group('not-follow-links', () {
test('dir-link', () {
expect(HttpServer.bind('localhost', 0).then((server) {
- var dir = new Directory('').createTempSync();
+ var dir =
+ Directory.systemTemp.createTempSync('http_server_virtual_');
var dir2 = new Directory('${dir.path}/dir2')..createSync();
var link = new Link('${dir.path}/dir3')..createSync('dir2');
var file = new File('${dir2.path}/file')..createSync();
@@ -348,7 +354,7 @@
group('file', () {
test('file-exists', () {
expect(HttpServer.bind('localhost', 0).then((server) {
- var dir = new Directory('').createTempSync();
+ var dir = Directory.systemTemp.createTempSync('http_server_virtual_');
var file = new File('${dir.path}/file')..createSync();
var virDir = new VirtualDirectory(dir.path);
@@ -373,7 +379,7 @@
test('file-changes', () {
expect(HttpServer.bind('localhost', 0).then((server) {
- var dir = new Directory('').createTempSync();
+ var dir = Directory.systemTemp.createTempSync('http_server_virtual_');
var file = new File('${dir.path}/file')..createSync();
var virDir = new VirtualDirectory(dir.path);
@@ -405,7 +411,7 @@
group('mime-type', () {
test('from-path', () {
expect(HttpServer.bind('localhost', 0).then((server) {
- var dir = new Directory('').createTempSync();
+ var dir = Directory.systemTemp.createTempSync('http_server_virtual_');
var file = new File('${dir.path}/file.jpg')..createSync();
var virDir = new VirtualDirectory(dir.path);
@@ -422,7 +428,7 @@
test('from-magic-number', () {
expect(HttpServer.bind('localhost', 0).then((server) {
- var dir = new Directory('').createTempSync();
+ var dir = Directory.systemTemp.createTempSync('http_server_virtual_');
var file = new File('${dir.path}/file.jpg')..createSync();
file.writeAsBytesSync(
[0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A]);
@@ -444,7 +450,7 @@
group('error-page', () {
test('default', () {
expect(HttpServer.bind('localhost', 0).then((server) {
- var dir = new Directory('').createTempSync();
+ var dir = Directory.systemTemp.createTempSync('http_server_virtual_');
var virDir = new VirtualDirectory(dir.path);
dir.deleteSync();
@@ -459,7 +465,7 @@
test('custom', () {
expect(HttpServer.bind('localhost', 0).then((server) {
- var dir = new Directory('').createTempSync();
+ var dir = Directory.systemTemp.createTempSync('http_server_virtual_');
var virDir = new VirtualDirectory(dir.path);
dir.deleteSync();
@@ -481,7 +487,7 @@
group('escape-root', () {
test('escape1', () {
expect(HttpServer.bind('localhost', 0).then((server) {
- var dir = new Directory('').createTempSync();
+ var dir = Directory.systemTemp.createTempSync('http_server_virtual_');
var virDir = new VirtualDirectory(dir.path);
virDir.allowDirectoryListing = true;
@@ -497,7 +503,7 @@
test('escape2', () {
expect(HttpServer.bind('localhost', 0).then((server) {
- var dir = new Directory('').createTempSync();
+ var dir = Directory.systemTemp.createTempSync('http_server_virtual_');
new Directory('${dir.path}/dir').createSync();
var virDir = new VirtualDirectory(dir.path);
virDir.allowDirectoryListing = true;
@@ -516,7 +522,7 @@
group('url-decode', () {
test('with-space', () {
expect(HttpServer.bind('localhost', 0).then((server) {
- var dir = new Directory('').createTempSync();
+ var dir = Directory.systemTemp.createTempSync('http_server_virtual_');
var file = new File('${dir.path}/my file')..createSync();
var virDir = new VirtualDirectory(dir.path);
@@ -532,7 +538,7 @@
test('encoded-space', () {
expect(HttpServer.bind('localhost', 0).then((server) {
- var dir = new Directory('').createTempSync();
+ var dir = Directory.systemTemp.createTempSync('http_server_virtual_');
var file = new File('${dir.path}/my file')..createSync();
var virDir = new VirtualDirectory(dir.path);
@@ -548,7 +554,7 @@
test('encoded-path-separator', () {
expect(HttpServer.bind('localhost', 0).then((server) {
- var dir = new Directory('').createTempSync();
+ var dir = Directory.systemTemp.createTempSync('http_server_virtual_');
new Directory('${dir.path}/a').createSync();
new Directory('${dir.path}/a/b').createSync();
new Directory('${dir.path}/a/b/c').createSync();
@@ -567,7 +573,7 @@
test('encoded-null', () {
expect(HttpServer.bind('localhost', 0).then((server) {
- var dir = new Directory('').createTempSync();
+ var dir = Directory.systemTemp.createTempSync('http_server_virtual_');
var virDir = new VirtualDirectory(dir.path);
virDir.allowDirectoryListing = true;
@@ -584,7 +590,7 @@
testEncoding(name, expected, [bool create = true]) {
test('encode-$name', () {
expect(HttpServer.bind('localhost', 0).then((server) {
- var dir = new Directory('').createTempSync();
+ var dir = Directory.systemTemp.createTempSync('http_server_virtual_');
if (create) new File('${dir.path}/$name').createSync();
var virDir = new VirtualDirectory(dir.path);
virDir.allowDirectoryListing = true;
diff --git a/pkg/pkg.status b/pkg/pkg.status
index d5c5205..7fed36f 100644
--- a/pkg/pkg.status
+++ b/pkg/pkg.status
@@ -240,3 +240,7 @@
[ $compiler == none && $runtime == vm && $checked ]
intl/test/message_extraction/failed_extraction_test: Pass, Fail # Issue 13543
+
+[ $compiler == none && $runtime == dartium ]
+source_maps/test/parser_test: Pass, Timeout # Issue 13719: Please triage this failure.
+
diff --git a/pkg/polymer/lib/platform.dart b/pkg/polymer/lib/platform.dart
index 5dc5c3e..f6c475a 100644
--- a/pkg/polymer/lib/platform.dart
+++ b/pkg/polymer/lib/platform.dart
@@ -11,6 +11,7 @@
// belong in html's Platform instead?
library polymer.platform;
+import 'dart:async' show Completer;
import 'dart:html' show Text, MutationObserver;
import 'dart:collection' show Queue;
import 'package:observe/src/microtask.dart' show performMicrotaskCheckpoint;
diff --git a/pkg/scheduled_test/lib/descriptor.dart b/pkg/scheduled_test/lib/descriptor.dart
index 6692591..0004236 100644
--- a/pkg/scheduled_test/lib/descriptor.dart
+++ b/pkg/scheduled_test/lib/descriptor.dart
@@ -46,7 +46,9 @@
/// setUp(() {
/// var tempDir;
/// schedule(() {
-/// return new Directory('').createTemp().then((dir) {
+/// return Directory.systemTemp
+/// .createTemp('my_temp_dir_')
+/// .then((dir) {
/// tempDir = dir;
/// d.defaultRoot = tempDir.path;
/// });
diff --git a/pkg/scheduled_test/test/descriptor/utils.dart b/pkg/scheduled_test/test/descriptor/utils.dart
index bd9ae57..9674469 100644
--- a/pkg/scheduled_test/test/descriptor/utils.dart
+++ b/pkg/scheduled_test/test/descriptor/utils.dart
@@ -16,7 +16,7 @@
void scheduleSandbox() {
schedule(() {
- return new Directory('').createTemp().then((dir) {
+ return Directory.systemTemp.createTemp('descriptor_sandbox_').then((dir) {
sandbox = dir.path;
d.defaultRoot = sandbox;
});
diff --git a/pkg/scheduled_test/test/scheduled_process_test.dart b/pkg/scheduled_test/test/scheduled_process_test.dart
index 92ebfad..f937ae8 100644
--- a/pkg/scheduled_test/test/scheduled_process_test.dart
+++ b/pkg/scheduled_test/test/scheduled_process_test.dart
@@ -357,10 +357,10 @@
}
ScheduledProcess startDartProcess(String script) {
- var tempDir = schedule(() {
- return new Directory('').createTemp().then((dir) => dir.path);
- }, 'create temp dir');
-
+ var tempDir = schedule(() => Directory.systemTemp
+ .createTemp('scheduled_process_test_')
+ .then((dir) => dir.path),
+ 'create temp dir');
var dartPath = schedule(() {
return tempDir.then((dir) {
var utilsPath = path.absolute(path.join(Platform.script, 'utils.dart'));
diff --git a/pkg/third_party/html5lib/lib/src/list_proxy.dart b/pkg/third_party/html5lib/lib/src/list_proxy.dart
index 99adb3f..786e393 100644
--- a/pkg/third_party/html5lib/lib/src/list_proxy.dart
+++ b/pkg/third_party/html5lib/lib/src/list_proxy.dart
@@ -51,6 +51,7 @@
void addLast(E value) { add(value); }
void addAll(Iterable<E> collection) { _list.addAll(collection); }
void sort([int compare(E a, E b)]) { _list.sort(compare); }
+ void shuffle() { _list.shuffle(); }
int indexOf(E element, [int start = 0]) => _list.indexOf(element, start);
int lastIndexOf(E element, [int start]) => _list.lastIndexOf(element, start);
diff --git a/pkg/unmodifiable_collection/lib/unmodifiable_collection.dart b/pkg/unmodifiable_collection/lib/unmodifiable_collection.dart
index b94a0c4..2388ccb 100644
--- a/pkg/unmodifiable_collection/lib/unmodifiable_collection.dart
+++ b/pkg/unmodifiable_collection/lib/unmodifiable_collection.dart
@@ -54,11 +54,12 @@
Map<int, E> asMap() => _source.asMap();
-
void operator []=(int index, E value) { _source[index] = value; }
void sort([int compare(E a, E b)]) { _source.sort(compare); }
+ void shuffle() { _source.shuffle(); }
+
void setRange(int start, int end, Iterable<E> iterable, [int skipCount = 0]) {
_source.setRange(start, end, iterable, skipCount);
}
@@ -154,7 +155,7 @@
/**
* An unmodifiable set.
*
- * An UnmodifiableSetView contains a [Set] object and ensures
+ * An UnmodifiableSetView contains a [Set] object and ensures
* that it does not change.
* Methods that would change the set,
* such as [add] and [remove], throw an [UnsupportedError].
@@ -230,7 +231,7 @@
/**
* An unmodifiable map.
*
- * An UnmodifiableMapView contains a [Map] object and ensures
+ * An UnmodifiableMapView contains a [Map] object and ensures
* that it does not change.
* Methods that would change the map,
* such as [addAll] and [remove], throw an [UnsupportedError].
diff --git a/pkg/utf/lib/utf.dart b/pkg/utf/lib/utf.dart
index 164c340..002287a 100644
--- a/pkg/utf/lib/utf.dart
+++ b/pkg/utf/lib/utf.dart
@@ -3,12 +3,14 @@
// BSD-style license that can be found in the LICENSE file.
/**
- * Support for encoding and decoding Unicode characters in UTF-8, UTF-16, and
+ * Support for encoding and decoding Unicode characters in UTF-8, UTF-16, and
* UTF-32.
*/
library utf;
+
import "dart:async";
import "dart:collection";
+
part "utf_stream.dart";
part "utf8.dart";
part "utf16.dart";
diff --git a/pkg/utf/lib/utf16.dart b/pkg/utf/lib/utf16.dart
index 3518bbb..7de9e61 100644
--- a/pkg/utf/lib/utf16.dart
+++ b/pkg/utf/lib/utf16.dart
@@ -2,7 +2,7 @@
// 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 dart.utf;
+part of utf;
/**
* Decodes the UTF-16 bytes as an iterable. Thus, the consumer can only convert
diff --git a/pkg/utf/lib/utf32.dart b/pkg/utf/lib/utf32.dart
index acd465c..885ed94 100644
--- a/pkg/utf/lib/utf32.dart
+++ b/pkg/utf/lib/utf32.dart
@@ -2,7 +2,7 @@
// 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 dart.utf;
+part of utf;
/**
* Decodes the UTF-32 bytes as an iterable. Thus, the consumer can only convert
@@ -70,7 +70,7 @@
String decodeUtf32be(
List<int> bytes, [int offset = 0, int length, bool stripBom = true,
int replacementCodepoint = UNICODE_REPLACEMENT_CHARACTER_CODEPOINT]) =>
- new String.fromCharCodes((new Utf32beBytesDecoder(bytes, offset, length,
+ new String.fromCharCodes((new Utf32beBytesDecoder(bytes, offset, length,
stripBom, replacementCodepoint)).decodeRest());
/**
diff --git a/pkg/utf/lib/utf8.dart b/pkg/utf/lib/utf8.dart
index 7543865..36288d9 100644
--- a/pkg/utf/lib/utf8.dart
+++ b/pkg/utf/lib/utf8.dart
@@ -2,7 +2,7 @@
// 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 dart.utf;
+part of utf;
const int _UTF8_ONE_BYTE_MAX = 0x7f;
const int _UTF8_TWO_BYTE_MAX = 0x7ff;
diff --git a/pkg/utf/lib/utf_stream.dart b/pkg/utf/lib/utf_stream.dart
index 8440313..cfc57b9 100644
--- a/pkg/utf/lib/utf_stream.dart
+++ b/pkg/utf/lib/utf_stream.dart
@@ -2,7 +2,7 @@
// 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 dart.utf;
+part of utf;
abstract class _StringDecoder
extends StreamEventTransformer<List<int>, String> {
diff --git a/pkg/watcher/test/utils.dart b/pkg/watcher/test/utils.dart
index 656ddf8..28d57b0 100644
--- a/pkg/watcher/test/utils.dart
+++ b/pkg/watcher/test/utils.dart
@@ -46,7 +46,7 @@
///
/// This should usually be called by [setUp].
void createSandbox() {
- var dir = new Directory("").createTempSync();
+ var dir = Directory.systemTemp.createTempSync('watcher_test_');
_sandboxDir = dir.path;
_mockFileModificationTimes = new Map<String, int>();
diff --git a/runtime/bin/builtin_natives.cc b/runtime/bin/builtin_natives.cc
index 48c10fb..eee4430 100644
--- a/runtime/bin/builtin_natives.cc
+++ b/runtime/bin/builtin_natives.cc
@@ -27,7 +27,8 @@
V(Directory_Create, 1) \
V(Directory_Current, 0) \
V(Directory_SetCurrent, 1) \
- V(Directory_CreateTemp, 2) \
+ V(Directory_SystemTemp, 0) \
+ V(Directory_CreateTemp, 1) \
V(Directory_Delete, 2) \
V(Directory_Rename, 2) \
V(Directory_List, 3) \
diff --git a/runtime/bin/dartutils.cc b/runtime/bin/dartutils.cc
index eabd4f3..9d33706 100644
--- a/runtime/bin/dartutils.cc
+++ b/runtime/bin/dartutils.cc
@@ -485,7 +485,8 @@
if (DartUtils::IsDartIOLibURL(url_string)) {
return Builtin::LoadAndCheckLibrary(Builtin::kIOLibrary);
}
- return Dart_Error("Do not know how to load '%s'", url_string);
+ return Dart_Error("The built-in library '%s' is not available"
+ " on the stand-alone VM.\n", url_string);
} else {
ASSERT(tag == Dart_kSourceTag);
return Dart_Error("Unable to load source '%s' ", url_string);
diff --git a/runtime/bin/directory.cc b/runtime/bin/directory.cc
index 6aa4d09..10c53b9 100644
--- a/runtime/bin/directory.cc
+++ b/runtime/bin/directory.cc
@@ -76,16 +76,22 @@
}
+void FUNCTION_NAME(Directory_SystemTemp)(
+ Dart_NativeArguments args) {
+ char* result = Directory::SystemTemp();
+ Dart_SetReturnValue(args, DartUtils::NewString(result));
+ free(result);
+}
+
+
void FUNCTION_NAME(Directory_CreateTemp)(Dart_NativeArguments args) {
Dart_Handle path = Dart_GetNativeArgument(args, 0);
- Dart_Handle system = Dart_GetNativeArgument(args, 1);
if (!Dart_IsString(path)) {
Dart_SetReturnValue(args, DartUtils::NewDartArgumentError(
- "Template argument of CreateSystemTempSync is not a String"));
+ "Prefix argument of CreateSystemTempSync is not a String"));
return;
}
- char* result = Directory::CreateTemp(DartUtils::GetStringValue(path),
- DartUtils::GetBooleanValue(system));
+ char* result = Directory::CreateTemp(DartUtils::GetStringValue(path));
if (result != NULL) {
Dart_SetReturnValue(args, DartUtils::NewString(result));
free(result);
@@ -195,23 +201,7 @@
CObject* Directory::CreateTempRequest(const CObjectArray& request) {
if (request.Length() == 1 && request[0]->IsString()) {
CObjectString path(request[0]);
- char* result = Directory::CreateTemp(path.CString(), false);
- if (result != NULL) {
- CObject* temp_dir = new CObjectString(CObject::NewString(result));
- free(result);
- return temp_dir;
- } else {
- return CObject::NewOSError();
- }
- }
- return CObject::IllegalArgumentError();
-}
-
-
-CObject* Directory::CreateSystemTempRequest(const CObjectArray& request) {
- if (request.Length() == 1 && request[0]->IsString()) {
- CObjectString path(request[0]);
- char* result = Directory::CreateTemp(path.CString(), true);
+ char* result = Directory::CreateTemp(path.CString());
if (result != NULL) {
CObject* temp_dir = new CObjectString(CObject::NewString(result));
free(result);
diff --git a/runtime/bin/directory.h b/runtime/bin/directory.h
index 57302a2..fd78e80 100644
--- a/runtime/bin/directory.h
+++ b/runtime/bin/directory.h
@@ -257,7 +257,8 @@
static char* Current();
static bool SetCurrent(const char* path);
static bool Create(const char* path);
- static char* CreateTemp(const char* const_template, bool system);
+ static char* SystemTemp();
+ static char* CreateTemp(const char* path);
static bool Delete(const char* path, bool recursive);
static bool Rename(const char* path, const char* new_path);
diff --git a/runtime/bin/directory_android.cc b/runtime/bin/directory_android.cc
index 6a2646a..7dd450a 100644
--- a/runtime/bin/directory_android.cc
+++ b/runtime/bin/directory_android.cc
@@ -382,34 +382,34 @@
}
-char* Directory::CreateTemp(const char* const_template, bool system) {
- // Returns a new, unused directory name, modifying the contents of
- // dir_template. Creates the directory with the permissions specified
+char* Directory::SystemTemp() {
+ // Android does not have a /tmp directory. A partial substitute,
+ // suitable for bring-up work and tests, is to create a tmp
+ // directory in /data/local/tmp.
+ //
+ // TODO(4413): In the long run, when running in an application we should
+ // probably use the appropriate directory from the Android API,
+ // probably what File.createTempFile uses.
+#define ANDROID_TEMP_DIR "/data/local/tmp"
+ struct stat st;
+ if (stat(ANDROID_TEMP_DIR, &st) != 0) {
+ mkdir(ANDROID_TEMP_DIR, 0777);
+ }
+ return strdup(ANDROID_TEMP_DIR);
+}
+
+
+char* Directory::CreateTemp(const char* prefix) {
+ // Returns a new, unused directory name, adding characters to the end
+ // of prefix. Creates the directory with the permissions specified
// by the process umask.
// The return value must be freed by the caller.
PathBuffer path;
- if (system) {
- // Android does not have a /tmp directory. A partial substitute,
- // suitable for bring-up work and tests, is to create a tmp
- // directory in /data/local/tmp.
- //
- // TODO(4413): In the long run, when running in an application we should
- // probably use the appropriate directory from the Android API,
- // probably what File.createTempFile uses.
- #define ANDROID_TEMP_DIR "/data/local/tmp"
- struct stat st;
- if (stat(ANDROID_TEMP_DIR, &st) != 0) {
- mkdir(ANDROID_TEMP_DIR, 0777);
- }
- path.Add(ANDROID_TEMP_DIR "/");
- }
-
- path.Add(const_template);
+ path.Add(prefix);
if (!path.Add("XXXXXX")) {
// Pattern has overflowed.
return NULL;
}
-
char* result;
do {
result = MakeTempDirectory(path.AsString());
@@ -417,11 +417,7 @@
if (result == NULL) {
return NULL;
}
- int length = strnlen(path.AsString(), PATH_MAX);
- result = static_cast<char*>(malloc(length + 1));
- strncpy(result, path.AsString(), length);
- result[length] = '\0';
- return result;
+ return strdup(result);
}
diff --git a/runtime/bin/directory_linux.cc b/runtime/bin/directory_linux.cc
index e12dbfd..c26289c 100644
--- a/runtime/bin/directory_linux.cc
+++ b/runtime/bin/directory_linux.cc
@@ -373,27 +373,31 @@
}
-char* Directory::CreateTemp(const char* const_template, bool system) {
- // Returns a new, unused directory name, modifying the contents of
- // dir_template. Creates the directory with the permissions specified
+char* Directory::SystemTemp() {
+ const char* temp_dir = getenv("TMPDIR");
+ if (temp_dir == NULL) {
+ temp_dir = getenv("TMP");
+ }
+ if (temp_dir == NULL) {
+ temp_dir = "/tmp";
+ }
+ char* result = strdup(temp_dir);
+ // Remove any trailing slash.
+ int length = strlen(result);
+ if (length > 1 && result[length - 1] == '/') {
+ result[length - 1] = '\0';
+ }
+ return result;
+}
+
+
+char* Directory::CreateTemp(const char* prefix) {
+ // Returns a new, unused directory name, adding characters to the end
+ // of prefix. Creates the directory with the permissions specified
// by the process umask.
// The return value must be freed by the caller.
PathBuffer path;
- if (system) {
- const char* temp_dir = getenv("TMPDIR");
- if (temp_dir == NULL) {
- temp_dir = getenv("TMP");
- }
- if (temp_dir != NULL) {
- path.Add(temp_dir);
- if (temp_dir[strlen(temp_dir) - 1] != '/') {
- path.Add("/");
- }
- } else {
- path.Add("/tmp/");
- }
- }
- path.Add(const_template);
+ path.Add(prefix);
if (!path.Add("XXXXXX")) {
// Pattern has overflowed.
return NULL;
@@ -405,11 +409,7 @@
if (result == NULL) {
return NULL;
}
- int length = strnlen(path.AsString(), PATH_MAX);
- result = static_cast<char*>(malloc(length + 1));
- strncpy(result, path.AsString(), length);
- result[length] = '\0';
- return result;
+ return strdup(result);
}
diff --git a/runtime/bin/directory_macos.cc b/runtime/bin/directory_macos.cc
index 5757a9c..074647f 100644
--- a/runtime/bin/directory_macos.cc
+++ b/runtime/bin/directory_macos.cc
@@ -361,27 +361,31 @@
}
-char* Directory::CreateTemp(const char* const_template, bool system) {
- // Returns a new, unused directory name, modifying the contents of
- // dir_template. Creates the directory with the permissions specified
+char* Directory::SystemTemp() {
+ const char* temp_dir = getenv("TMPDIR");
+ if (temp_dir == NULL) {
+ temp_dir = getenv("TMP");
+ }
+ if (temp_dir == NULL) {
+ temp_dir = "/tmp";
+ }
+ char* result = strdup(temp_dir);
+ // Remove any trailing slash.
+ int length = strlen(result);
+ if (length > 1 && result[length - 1] == '/') {
+ result[length - 1] = '\0';
+ }
+ return result;
+}
+
+
+char* Directory::CreateTemp(const char* prefix) {
+ // Returns a new, unused directory name, adding characters to the end
+ // of prefix. Creates the directory with the permissions specified
// by the process umask.
// The return value must be freed by the caller.
PathBuffer path;
- if (system) {
- const char* temp_dir = getenv("TMPDIR");
- if (temp_dir == NULL) {
- temp_dir = getenv("TMP");
- }
- if (temp_dir != NULL) {
- path.Add(temp_dir);
- if (temp_dir[strlen(temp_dir) - 1] != '/') {
- path.Add("/");
- }
- } else {
- path.Add("/tmp/");
- }
- }
- path.Add(const_template);
+ path.Add(prefix);
if (!path.Add("XXXXXX")) {
// Pattern has overflowed.
return NULL;
@@ -393,11 +397,7 @@
if (result == NULL) {
return NULL;
}
- int length = strlen(path.AsString());
- result = static_cast<char*>(malloc(length + 1));
- strncpy(result, path.AsString(), length);
- result[length] = '\0';
- return result;
+ return strdup(result);
}
diff --git a/runtime/bin/directory_patch.dart b/runtime/bin/directory_patch.dart
index f5961b9..f3d0dab 100644
--- a/runtime/bin/directory_patch.dart
+++ b/runtime/bin/directory_patch.dart
@@ -5,8 +5,8 @@
patch class _Directory {
/* patch */ static _current() native "Directory_Current";
/* patch */ static _setCurrent(path) native "Directory_SetCurrent";
- /* patch */ static _createTemp(String template, bool system)
- native "Directory_CreateTemp";
+ /* patch */ static _createTemp(String path) native "Directory_CreateTemp";
+ /* patch */ static String _systemTemp() native "Directory_SystemTemp";
/* patch */ static int _exists(String path) native "Directory_Exists";
/* patch */ static _create(String path) native "Directory_Create";
/* patch */ static _deleteNative(String path, bool recursive)
diff --git a/runtime/bin/directory_win.cc b/runtime/bin/directory_win.cc
index c72f4ef..e3e390f 100644
--- a/runtime/bin/directory_win.cc
+++ b/runtime/bin/directory_win.cc
@@ -383,21 +383,23 @@
}
-char* Directory::CreateTemp(const char* const_template, bool system) {
- // Returns a new, unused directory name, modifying the contents of
- // dir_template. Creates this directory, with a default security
+char* Directory::SystemTemp() {
+ PathBuffer path;
+ path.Reset(GetTempPathW(MAX_PATH, path.AsStringW()) - 1); // Remove \ at end.
+ return path.AsString();
+}
+
+
+char* Directory::CreateTemp(const char* prefix) {
+ // Returns a new, unused directory name, adding characters to the
+ // end of prefix.
+ // Creates this directory, with a default security
// descriptor inherited from its parent directory.
// The return value must be freed by the caller.
PathBuffer path;
- if (system) {
- path.Reset(GetTempPathW(MAX_PATH, path.AsStringW()));
- if (path.length() == 0) {
- return NULL;
- }
- }
- const wchar_t* system_template = StringUtils::Utf8ToWide(const_template);
- path.AddW(system_template);
- free(const_cast<wchar_t*>(system_template));
+ const wchar_t* system_prefix = StringUtils::Utf8ToWide(prefix);
+ path.AddW(system_prefix);
+ free(const_cast<wchar_t*>(system_prefix));
// Length of xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx is 36.
if (path.length() > MAX_PATH - 36) {
diff --git a/runtime/bin/io_service.h b/runtime/bin/io_service.h
index 8c1ba9f..d9e8c45 100644
--- a/runtime/bin/io_service.h
+++ b/runtime/bin/io_service.h
@@ -47,12 +47,11 @@
V(Directory, Delete, 30) \
V(Directory, Exists, 31) \
V(Directory, CreateTemp, 32) \
- V(Directory, CreateSystemTemp, 33) \
- V(Directory, ListStart, 34) \
- V(Directory, ListNext, 35) \
- V(Directory, ListStop, 36) \
- V(Directory, Rename, 37) \
- V(SSLFilter, ProcessFilter, 38)
+ V(Directory, ListStart, 33) \
+ V(Directory, ListNext, 34) \
+ V(Directory, ListStop, 35) \
+ V(Directory, Rename, 36) \
+ V(SSLFilter, ProcessFilter, 37)
#define DECLARE_REQUEST(type, method, id) \
k##type##method##Request = id,
diff --git a/runtime/bin/main.cc b/runtime/bin/main.cc
index 92e08ac..eae320d 100644
--- a/runtime/bin/main.cc
+++ b/runtime/bin/main.cc
@@ -630,6 +630,8 @@
Dart_ExitScope();
Dart_ShutdownIsolate();
+ Dart_Cleanup();
+
return exit_code;
}
@@ -799,8 +801,6 @@
result = Dart_CreateScriptSnapshot(&buffer, &size);
if (Dart_IsError(result)) {
Log::PrintErr("%s\n", Dart_GetError(result));
- Dart_ExitScope();
- Dart_ShutdownIsolate();
return DartErrorExit(result);
}
@@ -875,6 +875,8 @@
// Terminate process exit-code handler.
Process::TerminateExitCodeHandler();
+ Dart_Cleanup();
+
// Free copied argument strings if converted.
if (argv_converted) {
for (int i = 0; i < argc; i++) free(argv[i]);
diff --git a/runtime/include/dart_api.h b/runtime/include/dart_api.h
index 9f4969e..bcd3474 100755
--- a/runtime/include/dart_api.h
+++ b/runtime/include/dart_api.h
@@ -750,6 +750,13 @@
Dart_FileCloseCallback file_close);
/**
+ * Cleanup state in the VM before process termination.
+ *
+ * \return True if cleanup is successful.
+ */
+DART_EXPORT bool Dart_Cleanup();
+
+/**
* Sets command line flags. Should be called before Dart_Initialize.
*
* \param argc The length of the arguments array.
@@ -1822,6 +1829,30 @@
Dart_Handle* arguments);
/**
+ * Invokes a Generative Constructor on an object that was previously
+ * allocated using Dart_Allocate.
+ *
+ * The 'target' parameter must be an object.
+ *
+ * This function ignores visibility (leading underscores in names).
+ *
+ * May generate an unhandled exception error.
+ *
+ * \param target An object.
+ * \param name The name of the constructor to invoke.
+ * \param number_of_arguments Size of the arguments array.
+ * \param arguments An array of arguments to the function.
+ *
+ * \return If the constructor is called and completes
+ * successfully, then the object is returned. If an error
+ * occurs during execution, then an error handle is returned.
+ */
+DART_EXPORT Dart_Handle Dart_InvokeConstructor(Dart_Handle object,
+ Dart_Handle name,
+ int number_of_arguments,
+ Dart_Handle* arguments);
+
+/**
* Gets the value of a field.
*
* The 'container' parameter may be an object, type, or library. If
diff --git a/runtime/lib/array.dart b/runtime/lib/array.dart
index 89ddce5..fe9a15b 100644
--- a/runtime/lib/array.dart
+++ b/runtime/lib/array.dart
@@ -202,6 +202,10 @@
IterableMixinWorkaround.sortList(this, compare);
}
+ void shuffle() {
+ IterableMixinWorkaround.shuffleList(this);
+ }
+
int indexOf(Object element, [int start = 0]) {
return Arrays.indexOf(this, element, start, this.length);
}
@@ -456,6 +460,11 @@
"Cannot modify an immutable array");
}
+ void shuffle() {
+ throw new UnsupportedError(
+ "Cannot modify an immutable array");
+ }
+
String toString() {
return IterableMixinWorkaround.toStringIterable(this, '[', ']');
}
diff --git a/runtime/lib/growable_array.dart b/runtime/lib/growable_array.dart
index b1f1ccb..2a0ec88 100644
--- a/runtime/lib/growable_array.dart
+++ b/runtime/lib/growable_array.dart
@@ -336,6 +336,10 @@
IterableMixinWorkaround.sortList(this, compare);
}
+ void shuffle() {
+ IterableMixinWorkaround.shuffleList(this);
+ }
+
String toString() {
return IterableMixinWorkaround.toStringIterable(this, '[', ']');
}
diff --git a/runtime/lib/mirrors.cc b/runtime/lib/mirrors.cc
index 754aa5f..f6cb310 100644
--- a/runtime/lib/mirrors.cc
+++ b/runtime/lib/mirrors.cc
@@ -1064,18 +1064,6 @@
}
-DEFINE_NATIVE_ENTRY(InstanceMirror_identityHash, 1) {
- GET_NATIVE_ARGUMENT(Instance, reflectee, arguments->NativeArgAt(0));
- ObjectStore* object_store = isolate->object_store();
- const Class& cls = Class::Handle(isolate, object_store->object_class());
- const Function& function =
- Function::Handle(isolate, cls.LookupDynamicFunction(Symbols::hashCode()));
- const Array& args = Array::Handle(isolate, Array::New(1));
- args.SetAt(0, reflectee);
- return DartEntry::InvokeFunction(function, args);
-}
-
-
DEFINE_NATIVE_ENTRY(InstanceMirror_invoke, 5) {
// Argument 0 is the mirror, which is unused by the native. It exists
// because this native is an instance method in order to be polymorphic
diff --git a/runtime/lib/mirrors_impl.dart b/runtime/lib/mirrors_impl.dart
index e20aa88..858b2ee 100644
--- a/runtime/lib/mirrors_impl.dart
+++ b/runtime/lib/mirrors_impl.dart
@@ -302,21 +302,11 @@
}
int get hashCode {
- // If the reflectee is a double or bignum, use the base hashCode to preserve
- // the illusion that boxed numbers with the same value are identical. If the
- // reflectee is a Smi, use the base hashCode because Object.hashCode does
- // not work for non-heap objects. Otherwise, use Object.hashCode to maintain
- // correctness even if a user-defined hashCode returns different values for
- // successive invocations.
- var h = _reflectee is num ? _reflectee.hashCode : _identityHash(_reflectee);
// Avoid hash collisions with the reflectee. This constant is in Smi range
// and happens to be the inner padding from RFC 2104.
- return h ^ 0x36363636;
+ return identityHashCode(_reflectee) ^ 0x36363636;
}
- static _identityHash(reflectee)
- native "InstanceMirror_identityHash";
-
// Override to include the receiver in the arguments.
InstanceMirror invoke(Symbol memberName,
List positionalArguments,
diff --git a/runtime/lib/typed_data.dart b/runtime/lib/typed_data.dart
index 0f10690..9e2a114 100644
--- a/runtime/lib/typed_data.dart
+++ b/runtime/lib/typed_data.dart
@@ -407,7 +407,11 @@
}
void sort([int compare(num a, num b)]) {
- return IterableMixinWorkaround.sortList(this, compare);
+ IterableMixinWorkaround.sortList(this, compare);
+ }
+
+ void shuffle() {
+ IterableMixinWorkaround.shuffleList(this);
}
int indexOf(element, [int start = 0]) {
diff --git a/runtime/vm/bootstrap_natives.h b/runtime/vm/bootstrap_natives.h
index 48844b2..cd51087 100644
--- a/runtime/vm/bootstrap_natives.h
+++ b/runtime/vm/bootstrap_natives.h
@@ -256,7 +256,6 @@
V(Mirrors_makeLocalTypeMirror, 1) \
V(Mirrors_makeLocalMirrorSystem, 0) \
V(MirrorReference_equals, 2) \
- V(InstanceMirror_identityHash, 1) \
V(InstanceMirror_invoke, 5) \
V(InstanceMirror_invokeGetter, 3) \
V(InstanceMirror_invokeSetter, 4) \
diff --git a/runtime/vm/code_observers.cc b/runtime/vm/code_observers.cc
index 1e8835a..4873371 100644
--- a/runtime/vm/code_observers.cc
+++ b/runtime/vm/code_observers.cc
@@ -50,6 +50,8 @@
delete observers_[i];
}
free(observers_);
+ observers_length_ = 0;
+ observers_ = NULL;
}
diff --git a/runtime/vm/dart.cc b/runtime/vm/dart.cc
index af17f5e..e81438f 100644
--- a/runtime/vm/dart.cc
+++ b/runtime/vm/dart.cc
@@ -74,7 +74,6 @@
};
-// TODO(turnidge): We should add a corresponding Dart::Cleanup.
const char* Dart::InitOnce(Dart_IsolateCreateCallback create,
Dart_IsolateInterruptCallback interrupt,
Dart_IsolateUnhandledExceptionCallback unhandled,
@@ -144,6 +143,37 @@
}
+const char* Dart::Cleanup() {
+#if 0
+ // Ideally we should shutdown the VM isolate here, but the thread pool
+ // shutdown does not seem to ensure that all the threads have stopped
+ // execution before it terminates, this results in racing isolates.
+ if (vm_isolate_ == NULL) {
+ return "VM already terminated.";
+ }
+
+ ASSERT(Isolate::Current() == NULL);
+
+ delete thread_pool_;
+ thread_pool_ = NULL;
+
+ // Set the VM isolate as current isolate.
+ Isolate::SetCurrent(vm_isolate_);
+
+ // There is a planned and known asymmetry here: We exit one scope for the VM
+ // isolate to account for the scope that was entered in Dart_InitOnce.
+ Dart_ExitScope();
+
+ ShutdownIsolate();
+ vm_isolate_ = NULL;
+#endif
+
+ CodeObservers::DeleteAll();
+
+ return NULL;
+}
+
+
Isolate* Dart::CreateIsolate(const char* name_prefix) {
// Create a new isolate.
Isolate* isolate = Isolate::Init(name_prefix);
diff --git a/runtime/vm/dart.h b/runtime/vm/dart.h
index d1c592a..edb18ad 100644
--- a/runtime/vm/dart.h
+++ b/runtime/vm/dart.h
@@ -28,6 +28,7 @@
Dart_FileReadCallback file_read,
Dart_FileWriteCallback file_write,
Dart_FileCloseCallback file_close);
+ static const char* Cleanup();
static Isolate* CreateIsolate(const char* name_prefix);
static RawError* InitializeIsolate(const uint8_t* snapshot, void* data);
diff --git a/runtime/vm/dart_api_impl.cc b/runtime/vm/dart_api_impl.cc
index 680476e..44d8274 100644
--- a/runtime/vm/dart_api_impl.cc
+++ b/runtime/vm/dart_api_impl.cc
@@ -761,10 +761,23 @@
return true;
}
+
+DART_EXPORT bool Dart_Cleanup() {
+ CHECK_NO_ISOLATE(Isolate::Current());
+ const char* err_msg = Dart::Cleanup();
+ if (err_msg != NULL) {
+ OS::PrintErr("Dart_Cleanup: %s\n", err_msg);
+ return false;
+ }
+ return true;
+}
+
+
DART_EXPORT bool Dart_SetVMFlags(int argc, const char** argv) {
return Flags::ProcessCommandLineFlags(argc, argv);
}
+
DART_EXPORT bool Dart_IsVMFlagSet(const char* flag_name) {
if (Flags::Lookup(flag_name) != NULL) {
return true;
@@ -2974,6 +2987,115 @@
}
+static Dart_Handle SetupArguments(Isolate* isolate,
+ int num_args,
+ Dart_Handle* arguments,
+ int extra_args,
+ Array* args) {
+ // Check for malformed arguments in the arguments list.
+ *args = Array::New(num_args + extra_args);
+ Object& arg = Object::Handle(isolate);
+ for (int i = 0; i < num_args; i++) {
+ arg = Api::UnwrapHandle(arguments[i]);
+ if (!arg.IsNull() && !arg.IsInstance()) {
+ *args = Array::null();
+ if (arg.IsError()) {
+ return Api::NewHandle(isolate, arg.raw());
+ } else {
+ return Api::NewError(
+ "%s expects arguments[%d] to be an Instance handle.",
+ "Dart_Invoke", i);
+ }
+ }
+ args->SetAt((i + extra_args), arg);
+ }
+ return Api::Success();
+}
+
+
+DART_EXPORT Dart_Handle Dart_InvokeConstructor(Dart_Handle object,
+ Dart_Handle name,
+ int number_of_arguments,
+ Dart_Handle* arguments) {
+ Isolate* isolate = Isolate::Current();
+ DARTSCOPE(isolate);
+ CHECK_CALLBACK_STATE(isolate);
+
+ if (number_of_arguments < 0) {
+ return Api::NewError(
+ "%s expects argument 'number_of_arguments' to be non-negative.",
+ CURRENT_FUNC);
+ }
+ const String& constructor_name = Api::UnwrapStringHandle(isolate, name);
+ if (constructor_name.IsNull()) {
+ RETURN_TYPE_ERROR(isolate, name, String);
+ }
+ const Instance& instance = Api::UnwrapInstanceHandle(isolate, object);
+ if (instance.IsNull()) {
+ RETURN_TYPE_ERROR(isolate, object, Instance);
+ }
+
+ // Since we have allocated an object it would mean that all classes
+ // are finalized and hence it is not necessary to call
+ // Api::CheckIsolateState.
+ // TODO(asiva): How do we ensure that a constructor is not called more than
+ // once for the same object.
+
+ // Construct name of the constructor to invoke.
+ const Type& type_obj = Type::Handle(isolate, instance.GetType());
+ const Class& cls = Class::Handle(isolate, type_obj.type_class());
+ const String& class_name = String::Handle(isolate, cls.Name());
+ const Array& strings = Array::Handle(Array::New(3));
+ strings.SetAt(0, class_name);
+ strings.SetAt(1, Symbols::Dot());
+ strings.SetAt(2, constructor_name);
+ const String& dot_name = String::Handle(isolate, String::ConcatAll(strings));
+ const AbstractTypeArguments& type_arguments =
+ AbstractTypeArguments::Handle(isolate, type_obj.arguments());
+ const Function& constructor =
+ Function::Handle(isolate, cls.LookupFunctionAllowPrivate(dot_name));
+ const int extra_args = 2;
+ if (!constructor.IsNull() &&
+ constructor.IsConstructor() &&
+ constructor.AreValidArgumentCounts(number_of_arguments + extra_args,
+ 0,
+ NULL)) {
+ // Create the argument list.
+ // Constructors get the uninitialized object and a constructor phase.
+ if (!type_arguments.IsNull()) {
+ // The type arguments will be null if the class has no type
+ // parameters, in which case the following call would fail
+ // because there is no slot reserved in the object for the
+ // type vector.
+ instance.SetTypeArguments(type_arguments);
+ }
+ Dart_Handle result;
+ Array& args = Array::Handle(isolate);
+ result = SetupArguments(isolate,
+ number_of_arguments,
+ arguments,
+ extra_args,
+ &args);
+ if (!::Dart_IsError(result)) {
+ args.SetAt(0, instance);
+ args.SetAt(1, Smi::Handle(isolate, Smi::New(Function::kCtorPhaseAll)));
+ const Object& retval = Object::Handle(
+ isolate,
+ DartEntry::InvokeFunction(constructor, args));
+ if (retval.IsError()) {
+ result = Api::NewHandle(isolate, retval.raw());
+ } else {
+ result = Api::NewHandle(isolate, instance.raw());
+ }
+ }
+ return result;
+ }
+ return Api::NewError(
+ "%s expects argument 'name' to be a valid constructor.",
+ CURRENT_FUNC);
+}
+
+
DART_EXPORT Dart_Handle Dart_Invoke(Dart_Handle target,
Dart_Handle name,
int number_of_arguments,
@@ -2995,27 +3117,8 @@
if (obj.IsError()) {
return target;
}
-
- // Check for malformed arguments in the arguments list.
- intptr_t num_receiver =
- (obj.IsNull() || (obj.IsInstance() && !obj.IsType())) ? 1 : 0;
- const Array& args =
- Array::Handle(isolate, Array::New(number_of_arguments + num_receiver));
- Object& arg = Object::Handle(isolate);
- for (int i = 0; i < number_of_arguments; i++) {
- arg = Api::UnwrapHandle(arguments[i]);
- if (!arg.IsNull() && !arg.IsInstance()) {
- if (arg.IsError()) {
- return Api::NewHandle(isolate, arg.raw());
- } else {
- return Api::NewError(
- "%s expects arguments[%d] to be an Instance handle.",
- CURRENT_FUNC, i);
- }
- }
- args.SetAt((i + num_receiver), arg);
- }
-
+ Dart_Handle result;
+ Array& args = Array::Handle(isolate);
if (obj.IsType()) {
// Finalize all classes.
Dart_Handle state = Api::CheckIsolateState(isolate);
@@ -3038,9 +3141,17 @@
cls_name.ToCString(),
function_name.ToCString());
}
- return Api::NewHandle(isolate, DartEntry::InvokeFunction(function, args));
-
+ // Setup args and check for malformed arguments in the arguments list.
+ result = SetupArguments(isolate, number_of_arguments, arguments, 0, &args);
+ if (!::Dart_IsError(result)) {
+ result = Api::NewHandle(isolate,
+ DartEntry::InvokeFunction(function, args));
+ }
+ return result;
} else if (obj.IsNull() || obj.IsInstance()) {
+ // Since we have allocated an object it would mean that all classes
+ // are finalized and hence it is not necessary to call
+ // Api::CheckIsolateState.
Instance& instance = Instance::Handle(isolate);
instance ^= obj.raw();
ArgumentsDescriptor args_desc(
@@ -3048,18 +3159,33 @@
const Function& function = Function::Handle(
isolate,
Resolver::ResolveDynamic(instance, function_name, args_desc));
- args.SetAt(0, instance);
if (function.IsNull()) {
- const Array& args_descriptor =
+ // Setup args and check for malformed arguments in the arguments list.
+ result = SetupArguments(isolate,
+ number_of_arguments,
+ arguments,
+ 1,
+ &args);
+ if (!::Dart_IsError(result)) {
+ args.SetAt(0, instance);
+ const Array& args_descriptor =
Array::Handle(ArgumentsDescriptor::New(args.Length()));
- return Api::NewHandle(isolate,
- DartEntry::InvokeNoSuchMethod(instance,
- function_name,
- args,
- args_descriptor));
+ result = Api::NewHandle(isolate,
+ DartEntry::InvokeNoSuchMethod(instance,
+ function_name,
+ args,
+ args_descriptor));
+ }
+ return result;
}
- return Api::NewHandle(isolate, DartEntry::InvokeFunction(function, args));
-
+ // Setup args and check for malformed arguments in the arguments list.
+ result = SetupArguments(isolate, number_of_arguments, arguments, 1, &args);
+ if (!::Dart_IsError(result)) {
+ args.SetAt(0, instance);
+ result = Api::NewHandle(isolate,
+ DartEntry::InvokeFunction(function, args));
+ }
+ return result;
} else if (obj.IsLibrary()) {
// Check whether class finalization is needed.
const Library& lib = Library::Cast(obj);
@@ -3089,8 +3215,13 @@
function_name.ToCString(),
error_message.ToCString());
}
- return Api::NewHandle(isolate, DartEntry::InvokeFunction(function, args));
-
+ // Setup args and check for malformed arguments in the arguments list.
+ result = SetupArguments(isolate, number_of_arguments, arguments, 0, &args);
+ if (!::Dart_IsError(result)) {
+ result = Api::NewHandle(isolate,
+ DartEntry::InvokeFunction(function, args));
+ }
+ return result;
} else {
return Api::NewError(
"%s expects argument 'target' to be an object, type, or library.",
diff --git a/runtime/vm/dart_api_impl_test.cc b/runtime/vm/dart_api_impl_test.cc
index aa860ea..53da807 100644
--- a/runtime/vm/dart_api_impl_test.cc
+++ b/runtime/vm/dart_api_impl_test.cc
@@ -3844,12 +3844,12 @@
EXPECT_EQ(7, int_value);
// Allocate without a constructor.
- result = Dart_Allocate(type);
- EXPECT_VALID(result);
+ Dart_Handle obj = Dart_Allocate(type);
+ EXPECT_VALID(obj);
instanceof = false;
- EXPECT_VALID(Dart_ObjectIsType(result, type, &instanceof));
+ EXPECT_VALID(Dart_ObjectIsType(obj, type, &instanceof));
EXPECT(instanceof);
- foo = Dart_GetField(result, NewString("foo"));
+ foo = Dart_GetField(obj, NewString("foo"));
EXPECT(Dart_IsNull(foo));
// Invoke the unnamed constructor with an empty string.
@@ -3863,6 +3863,19 @@
EXPECT_VALID(Dart_IntegerToInt64(foo, &int_value));
EXPECT_EQ(7, int_value);
+ // Allocate object and invoke the unnamed constructor with an empty string.
+ obj = Dart_Allocate(type);
+ EXPECT_VALID(obj);
+ instanceof = false;
+ EXPECT_VALID(Dart_ObjectIsType(obj, type, &instanceof));
+ EXPECT(instanceof);
+ result = Dart_InvokeConstructor(obj, NewString(""), 0, NULL);
+ EXPECT_VALID(result);
+ int_value = 0;
+ foo = Dart_GetField(result, NewString("foo"));
+ EXPECT_VALID(Dart_IntegerToInt64(foo, &int_value));
+ EXPECT_EQ(7, int_value);
+
// Invoke a named constructor.
result = Dart_New(type, NewString("named"), 1, args);
EXPECT_VALID(result);
@@ -3873,6 +3886,19 @@
EXPECT_VALID(Dart_IntegerToInt64(foo, &int_value));
EXPECT_EQ(11, int_value);
+ // Allocate object and invoke a named constructor.
+ obj = Dart_Allocate(type);
+ EXPECT_VALID(obj);
+ instanceof = false;
+ EXPECT_VALID(Dart_ObjectIsType(obj, type, &instanceof));
+ EXPECT(instanceof);
+ result = Dart_InvokeConstructor(obj, NewString("named"), 1, args);
+ EXPECT_VALID(result);
+ int_value = 0;
+ foo = Dart_GetField(result, NewString("foo"));
+ EXPECT_VALID(Dart_IntegerToInt64(foo, &int_value));
+ EXPECT_EQ(11, int_value);
+
// Invoke a hidden named constructor.
result = Dart_New(type, NewString("_hidden"), 1, args);
EXPECT_VALID(result);
@@ -3883,6 +3909,28 @@
EXPECT_VALID(Dart_IntegerToInt64(foo, &int_value));
EXPECT_EQ(-11, int_value);
+ // Allocate object and invoke a hidden named constructor.
+ obj = Dart_Allocate(type);
+ EXPECT_VALID(obj);
+ instanceof = false;
+ EXPECT_VALID(Dart_ObjectIsType(obj, type, &instanceof));
+ EXPECT(instanceof);
+ result = Dart_InvokeConstructor(obj, NewString("_hidden"), 1, args);
+ EXPECT_VALID(result);
+ int_value = 0;
+ foo = Dart_GetField(result, NewString("foo"));
+ EXPECT_VALID(Dart_IntegerToInt64(foo, &int_value));
+ EXPECT_EQ(-11, int_value);
+
+ // Allocate object and Invoke a constructor which throws an exception.
+ obj = Dart_Allocate(type);
+ EXPECT_VALID(obj);
+ instanceof = false;
+ EXPECT_VALID(Dart_ObjectIsType(obj, type, &instanceof));
+ EXPECT(instanceof);
+ result = Dart_InvokeConstructor(obj, NewString("exception"), 1, args);
+ EXPECT_ERROR(result, "ConstructorDeath");
+
// Invoke a factory constructor.
result = Dart_New(type, NewString("multiply"), 1, args);
EXPECT_VALID(result);
diff --git a/runtime/vm/flow_graph_builder.cc b/runtime/vm/flow_graph_builder.cc
index 69199f0..4cb67db 100644
--- a/runtime/vm/flow_graph_builder.cc
+++ b/runtime/vm/flow_graph_builder.cc
@@ -970,13 +970,26 @@
temp_index(),
node->left()->token_pos());
node->left()->Visit(&for_left);
- EffectGraphVisitor for_right(owner(), temp_index());
- node->right()->Visit(&for_right);
EffectGraphVisitor empty(owner(), temp_index());
- if (node->kind() == Token::kAND) {
- Join(for_left, for_right, empty);
+ if (FLAG_enable_type_checks) {
+ ValueGraphVisitor for_right(owner(), temp_index());
+ node->right()->Visit(&for_right);
+ Value* right_value = for_right.value();
+ for_right.Do(new AssertBooleanInstr(node->right()->token_pos(),
+ right_value));
+ if (node->kind() == Token::kAND) {
+ Join(for_left, for_right, empty);
+ } else {
+ Join(for_left, empty, for_right);
+ }
} else {
- Join(for_left, empty, for_right);
+ EffectGraphVisitor for_right(owner(), temp_index());
+ node->right()->Visit(&for_right);
+ if (node->kind() == Token::kAND) {
+ Join(for_left, for_right, empty);
+ } else {
+ Join(for_left, empty, for_right);
+ }
}
return;
}
diff --git a/runtime/vm/flow_graph_inliner.cc b/runtime/vm/flow_graph_inliner.cc
index 83a631b..2a1a485 100644
--- a/runtime/vm/flow_graph_inliner.cc
+++ b/runtime/vm/flow_graph_inliner.cc
@@ -1163,7 +1163,8 @@
Definition* last;
if (optimizer.TryInlineRecognizedMethod(target,
call_,
- call_->ic_data(),
+ call_->instance_call()->token_pos(),
+ *call_->instance_call()->ic_data(),
&entry, &last)) {
// Create a graph fragment.
InlineExitCollector* exit_collector =
diff --git a/runtime/vm/flow_graph_optimizer.cc b/runtime/vm/flow_graph_optimizer.cc
index b9f6bd4..f2d9c90 100644
--- a/runtime/vm/flow_graph_optimizer.cc
+++ b/runtime/vm/flow_graph_optimizer.cc
@@ -687,21 +687,6 @@
}
-static intptr_t ReceiverClassId(InstanceCallInstr* call) {
- if (!call->HasICData()) return kIllegalCid;
-
- const ICData& ic_data = ICData::Handle(call->ic_data()->AsUnaryClassChecks());
-
- if (ic_data.NumberOfChecks() != 1) return kIllegalCid;
- ASSERT(ic_data.HasOneTarget());
-
- Function& target = Function::Handle();
- intptr_t class_id;
- ic_data.GetOneClassCheckAt(0, &class_id, &target);
- return class_id;
-}
-
-
void FlowGraphOptimizer::AddCheckSmi(Definition* to_check,
intptr_t deopt_id,
Environment* deopt_environment,
@@ -715,19 +700,24 @@
}
+Instruction* FlowGraphOptimizer::GetCheckClass(Definition* to_check,
+ const ICData& unary_checks,
+ intptr_t deopt_id) {
+ if ((unary_checks.NumberOfChecks() == 1) &&
+ (unary_checks.GetReceiverClassIdAt(0) == kSmiCid)) {
+ return new CheckSmiInstr(new Value(to_check), deopt_id);
+ }
+ return new CheckClassInstr(new Value(to_check), deopt_id, unary_checks);
+}
+
+
void FlowGraphOptimizer::AddCheckClass(Definition* to_check,
const ICData& unary_checks,
intptr_t deopt_id,
Environment* deopt_environment,
Instruction* insert_before) {
// Type propagation has not run yet, we cannot eliminate the check.
- Instruction* check = NULL;
- if ((unary_checks.NumberOfChecks() == 1) &&
- (unary_checks.GetReceiverClassIdAt(0) == kSmiCid)) {
- check = new CheckSmiInstr(new Value(to_check), deopt_id);
- } else {
- check = new CheckClassInstr(new Value(to_check), deopt_id, unary_checks);
- }
+ Instruction* check = GetCheckClass(to_check, unary_checks, deopt_id);
InsertBefore(insert_before, check, deopt_environment, Definition::kEffect);
}
@@ -741,75 +731,19 @@
}
-static bool ArgIsAlwaysSmi(const ICData& ic_data, intptr_t arg_n) {
- ASSERT(ic_data.num_args_tested() > arg_n);
- if (ic_data.NumberOfChecks() == 0) return false;
- GrowableArray<intptr_t> class_ids;
- Function& target = Function::Handle();
- const intptr_t len = ic_data.NumberOfChecks();
- for (intptr_t i = 0; i < len; i++) {
- ic_data.GetCheckAt(i, &class_ids, &target);
- if (class_ids[arg_n] != kSmiCid) return false;
+static bool ArgIsAlways(intptr_t cid,
+ const ICData& ic_data,
+ intptr_t arg_number) {
+ ASSERT(ic_data.num_args_tested() > arg_number);
+ const intptr_t num_checks = ic_data.NumberOfChecks();
+ if (num_checks == 0) return false;
+ for (intptr_t i = 0; i < num_checks; i++) {
+ if (ic_data.GetClassIdAt(i, arg_number) != cid) return false;
}
return true;
}
-// Returns array classid to load from, array and index value
-
-intptr_t FlowGraphOptimizer::PrepareIndexedOp(InstanceCallInstr* call,
- intptr_t class_id,
- Definition** array,
- Definition** index) {
- // Insert class check and index smi checks and attach a copy of the
- // original environment because the operation can still deoptimize.
- AddReceiverCheck(call);
- InsertBefore(call,
- new CheckSmiInstr(new Value(*index), call->deopt_id()),
- call->env(),
- Definition::kEffect);
-
- // Insert array length load and bounds check.
- const bool is_immutable =
- CheckArrayBoundInstr::IsFixedLengthArrayType(class_id);
- LoadFieldInstr* length =
- new LoadFieldInstr(new Value(*array),
- CheckArrayBoundInstr::LengthOffsetFor(class_id),
- Type::ZoneHandle(Type::SmiType()),
- is_immutable);
- length->set_result_cid(kSmiCid);
- length->set_recognized_kind(
- LoadFieldInstr::RecognizedKindFromArrayCid(class_id));
- InsertBefore(call, length, NULL, Definition::kValue);
- InsertBefore(call,
- new CheckArrayBoundInstr(new Value(length),
- new Value(*index),
- call->deopt_id()),
- call->env(),
- Definition::kEffect);
-
- if (class_id == kGrowableObjectArrayCid) {
- // Insert data elements load.
- LoadFieldInstr* elements =
- new LoadFieldInstr(new Value(*array),
- GrowableObjectArray::data_offset(),
- Type::ZoneHandle(Type::DynamicType()));
- elements->set_result_cid(kArrayCid);
- InsertBefore(call, elements, NULL, Definition::kValue);
- *array = elements;
- return kArrayCid;
- }
- if (RawObject::IsExternalTypedDataClassId(class_id)) {
- LoadUntaggedInstr* elements =
- new LoadUntaggedInstr(new Value(*array),
- ExternalTypedData::data_offset());
- InsertBefore(call, elements, NULL, Definition::kValue);
- *array = elements;
- }
- return class_id;
-}
-
-
static bool CanUnboxInt32() {
// Int32/Uint32 can be unboxed if it fits into a smi or the platform
// supports unboxed mints.
@@ -817,97 +751,144 @@
}
-bool FlowGraphOptimizer::TryReplaceWithStoreIndexed(InstanceCallInstr* call) {
- const intptr_t class_id = ReceiverClassId(call);
- ICData& value_check = ICData::ZoneHandle();
- switch (class_id) {
- case kArrayCid:
- case kGrowableObjectArrayCid:
- if (ArgIsAlwaysSmi(*call->ic_data(), 2)) {
- value_check = call->ic_data()->AsUnaryClassChecksForArgNr(2);
- }
- break;
- case kTypedDataInt8ArrayCid:
- case kTypedDataUint8ArrayCid:
- case kTypedDataUint8ClampedArrayCid:
- case kExternalTypedDataUint8ArrayCid:
- case kExternalTypedDataUint8ClampedArrayCid:
- case kTypedDataInt16ArrayCid:
- case kTypedDataUint16ArrayCid:
- // Check that value is always smi.
- value_check = call->ic_data()->AsUnaryClassChecksForArgNr(2);
- if ((value_check.NumberOfChecks() != 1) ||
- (value_check.GetReceiverClassIdAt(0) != kSmiCid)) {
- return false;
- }
- break;
- case kTypedDataInt32ArrayCid:
- case kTypedDataUint32ArrayCid: {
- if (!CanUnboxInt32()) return false;
- // Check that value is always smi or mint, if the platform has unboxed
- // mints (ia32 with at least SSE 4.1).
- value_check = call->ic_data()->AsUnaryClassChecksForArgNr(2);
- for (intptr_t i = 0; i < value_check.NumberOfChecks(); i++) {
- intptr_t cid = value_check.GetReceiverClassIdAt(i);
- if (FlowGraphCompiler::SupportsUnboxedMints()) {
- if ((cid != kSmiCid) && (cid != kMintCid)) {
- return false;
- }
- } else if (cid != kSmiCid) {
- return false;
- }
- }
- break;
- }
- case kTypedDataFloat32ArrayCid:
- case kTypedDataFloat64ArrayCid: {
- // Check that value is always double.
- value_check = call->ic_data()->AsUnaryClassChecksForArgNr(2);
- if ((value_check.NumberOfChecks() != 1) ||
- (value_check.GetReceiverClassIdAt(0) != kDoubleCid)) {
- return false;
- }
- break;
- }
- case kTypedDataFloat32x4ArrayCid: {
- if (!ShouldInlineSimd()) {
- return false;
- }
- // Check that value is always a Float32x4.
- value_check = call->ic_data()->AsUnaryClassChecksForArgNr(2);
- if ((value_check.NumberOfChecks() != 1) ||
- (value_check.GetReceiverClassIdAt(0) != kFloat32x4Cid)) {
- return false;
- }
- }
- break;
- default:
- // TODO(fschneider): Add support for other array types.
- return false;
- }
+static intptr_t MethodKindToCid(MethodRecognizer::Kind kind) {
+ switch (kind) {
+ case MethodRecognizer::kImmutableArrayGetIndexed:
+ return kImmutableArrayCid;
- BuildStoreIndexed(call, value_check, class_id);
+ case MethodRecognizer::kObjectArrayGetIndexed:
+ case MethodRecognizer::kObjectArraySetIndexed:
+ return kArrayCid;
+
+ case MethodRecognizer::kGrowableArrayGetIndexed:
+ case MethodRecognizer::kGrowableArraySetIndexed:
+ return kGrowableObjectArrayCid;
+
+ case MethodRecognizer::kFloat32ArrayGetIndexed:
+ case MethodRecognizer::kFloat32ArraySetIndexed:
+ return kTypedDataFloat32ArrayCid;
+
+ case MethodRecognizer::kFloat64ArrayGetIndexed:
+ case MethodRecognizer::kFloat64ArraySetIndexed:
+ return kTypedDataFloat64ArrayCid;
+
+ case MethodRecognizer::kInt8ArrayGetIndexed:
+ case MethodRecognizer::kInt8ArraySetIndexed:
+ return kTypedDataInt8ArrayCid;
+
+ case MethodRecognizer::kUint8ArrayGetIndexed:
+ case MethodRecognizer::kUint8ArraySetIndexed:
+ return kTypedDataUint8ArrayCid;
+
+ case MethodRecognizer::kUint8ClampedArrayGetIndexed:
+ case MethodRecognizer::kUint8ClampedArraySetIndexed:
+ return kTypedDataUint8ClampedArrayCid;
+
+ case MethodRecognizer::kExternalUint8ArrayGetIndexed:
+ case MethodRecognizer::kExternalUint8ArraySetIndexed:
+ return kExternalTypedDataUint8ArrayCid;
+
+ case MethodRecognizer::kExternalUint8ClampedArrayGetIndexed:
+ case MethodRecognizer::kExternalUint8ClampedArraySetIndexed:
+ return kExternalTypedDataUint8ClampedArrayCid;
+
+ case MethodRecognizer::kInt16ArrayGetIndexed:
+ case MethodRecognizer::kInt16ArraySetIndexed:
+ return kTypedDataInt16ArrayCid;
+
+ case MethodRecognizer::kUint16ArrayGetIndexed:
+ case MethodRecognizer::kUint16ArraySetIndexed:
+ return kTypedDataUint16ArrayCid;
+
+ case MethodRecognizer::kInt32ArrayGetIndexed:
+ case MethodRecognizer::kInt32ArraySetIndexed:
+ return kTypedDataInt32ArrayCid;
+
+ case MethodRecognizer::kUint32ArrayGetIndexed:
+ case MethodRecognizer::kUint32ArraySetIndexed:
+ return kTypedDataUint32ArrayCid;
+
+ case MethodRecognizer::kFloat32x4ArrayGetIndexed:
+ case MethodRecognizer::kFloat32x4ArraySetIndexed:
+ return kTypedDataFloat32x4ArrayCid;
+
+ default:
+ break;
+ }
+ return kIllegalCid;
+}
+
+
+bool FlowGraphOptimizer::TryReplaceWithStoreIndexed(InstanceCallInstr* call) {
+ // Check for monomorphic IC data.
+ if (!call->HasICData()) return false;
+ const ICData& ic_data = ICData::Handle(call->ic_data()->AsUnaryClassChecks());
+ if (ic_data.NumberOfChecks() != 1) return false;
+ ASSERT(ic_data.HasOneTarget());
+
+ const Function& target = Function::Handle(ic_data.GetTargetAt(0));
+ TargetEntryInstr* entry;
+ Definition* last;
+ if (!TryInlineRecognizedMethod(target,
+ call,
+ call->token_pos(),
+ *call->ic_data(),
+ &entry, &last)) {
+ return false;
+ }
+ // Insert receiver class check.
+ AddReceiverCheck(call);
+ // Remove the original push arguments.
+ for (intptr_t i = 0; i < call->ArgumentCount(); ++i) {
+ PushArgumentInstr* push = call->PushArgumentAt(i);
+ push->ReplaceUsesWith(push->value()->definition());
+ push->RemoveFromGraph();
+ }
+ // Replace all uses of this definition with the result.
+ call->ReplaceUsesWith(last);
+ // Finally insert the sequence other definition in place of this one in the
+ // graph.
+ call->previous()->LinkTo(entry->next());
+ entry->UnuseAllInputs(); // Entry block is not in the graph.
+ last->LinkTo(call);
+ // Remove through the iterator.
+ ASSERT(current_iterator()->Current() == call);
+ current_iterator()->RemoveCurrentFromGraph();
+ call->set_previous(NULL);
+ call->set_next(NULL);
return true;
}
-void FlowGraphOptimizer::BuildStoreIndexed(InstanceCallInstr* call,
- const ICData& value_check,
- intptr_t class_id) {
+bool FlowGraphOptimizer::InlineSetIndexed(
+ MethodRecognizer::Kind kind,
+ const Function& target,
+ Instruction* call,
+ intptr_t token_pos,
+ const ICData* ic_data,
+ const ICData& value_check,
+ TargetEntryInstr** entry,
+ Definition** last) {
+ intptr_t array_cid = MethodKindToCid(kind);
+ ASSERT(array_cid != kIllegalCid);
+
Definition* array = call->ArgumentAt(0);
Definition* index = call->ArgumentAt(1);
Definition* stored_value = call->ArgumentAt(2);
+
+ *entry = new TargetEntryInstr(flow_graph()->allocate_block_id(),
+ call->GetBlock()->try_index());
+ (*entry)->InheritDeoptTarget(call);
+ Instruction* cursor = *entry;
if (FLAG_enable_type_checks) {
// Only type check for the value. A type check for the index is not
// needed here because we insert a deoptimizing smi-check for the case
// the index is not a smi.
- const Function& target =
- Function::ZoneHandle(call->ic_data()->GetTargetAt(0));
const AbstractType& value_type =
AbstractType::ZoneHandle(target.ParameterTypeAt(2));
Definition* instantiator = NULL;
Definition* type_args = NULL;
- switch (class_id) {
+ switch (array_cid) {
case kArrayCid:
case kGrowableObjectArrayCid: {
const Class& instantiator_class = Class::Handle(target.Owner());
@@ -917,7 +898,11 @@
new LoadFieldInstr(new Value(array),
type_arguments_field_offset,
Type::ZoneHandle()); // No type.
- InsertBefore(call, load_type_args, NULL, Definition::kValue);
+ cursor = flow_graph()->AppendTo(cursor,
+ load_type_args,
+ NULL,
+ Definition::kValue);
+
instantiator = array;
type_args = load_type_args;
break;
@@ -936,15 +921,15 @@
case kTypedDataFloat32ArrayCid:
case kTypedDataFloat64ArrayCid: {
type_args = instantiator = flow_graph_->constant_null();
- ASSERT((class_id != kTypedDataFloat32ArrayCid &&
- class_id != kTypedDataFloat64ArrayCid) ||
+ ASSERT((array_cid != kTypedDataFloat32ArrayCid &&
+ array_cid != kTypedDataFloat64ArrayCid) ||
value_type.IsDoubleType());
ASSERT(value_type.IsInstantiated());
break;
}
case kTypedDataFloat32x4ArrayCid: {
type_args = instantiator = flow_graph_->constant_null();
- ASSERT((class_id != kTypedDataFloat32x4ArrayCid) ||
+ ASSERT((array_cid != kTypedDataFloat32x4ArrayCid) ||
value_type.IsFloat32x4Type());
ASSERT(value_type.IsInstantiated());
break;
@@ -954,7 +939,7 @@
UNREACHABLE();
}
AssertAssignableInstr* assert_value =
- new AssertAssignableInstr(call->token_pos(),
+ new AssertAssignableInstr(token_pos,
new Value(stored_value),
new Value(instantiator),
new Value(type_args),
@@ -964,10 +949,18 @@
// must have a deoptimization id that is valid for lookup in the unoptimized
// code.
assert_value->deopt_id_ = call->deopt_id();
- InsertBefore(call, assert_value, call->env(), Definition::kValue);
+ cursor = flow_graph()->AppendTo(cursor,
+ assert_value,
+ call->env(),
+ Definition::kValue);
}
- intptr_t array_cid = PrepareIndexedOp(call, class_id, &array, &index);
+ array_cid = PrepareInlineIndexedOp(call,
+ array_cid,
+ &array,
+ index,
+ &cursor);
+
// Check if store barrier is needed. Byte arrays don't need a store barrier.
StoreBarrierType needs_store_barrier =
(RawObject::IsTypedDataClassId(array_cid) ||
@@ -978,83 +971,40 @@
// No store barrier needed because checked value is a smi, an unboxed mint,
// an unboxed double, an unboxed Float32x4, or unboxed Uint32x4.
needs_store_barrier = kNoStoreBarrier;
- AddCheckClass(stored_value, value_check, call->deopt_id(), call->env(),
- call);
+ Instruction* check =
+ GetCheckClass(stored_value, value_check, call->deopt_id());
+ cursor = flow_graph()->AppendTo(cursor,
+ check,
+ call->env(),
+ Definition::kEffect);
}
intptr_t index_scale = FlowGraphCompiler::ElementSizeFor(array_cid);
- Definition* array_op = new StoreIndexedInstr(new Value(array),
- new Value(index),
- new Value(stored_value),
- needs_store_barrier,
- index_scale,
- array_cid,
- call->deopt_id());
- ReplaceCall(call, array_op);
-}
-
-
-static intptr_t MethodKindToCid(MethodRecognizer::Kind kind) {
- switch (kind) {
- case MethodRecognizer::kImmutableArrayGetIndexed:
- return kImmutableArrayCid;
-
- case MethodRecognizer::kObjectArrayGetIndexed:
- return kArrayCid;
-
- case MethodRecognizer::kGrowableArrayGetIndexed:
- return kGrowableObjectArrayCid;
-
- case MethodRecognizer::kFloat32ArrayGetIndexed:
- return kTypedDataFloat32ArrayCid;
-
- case MethodRecognizer::kFloat64ArrayGetIndexed:
- return kTypedDataFloat64ArrayCid;
-
- case MethodRecognizer::kInt8ArrayGetIndexed:
- return kTypedDataInt8ArrayCid;
-
- case MethodRecognizer::kUint8ArrayGetIndexed:
- return kTypedDataUint8ArrayCid;
-
- case MethodRecognizer::kUint8ClampedArrayGetIndexed:
- return kTypedDataUint8ClampedArrayCid;
-
- case MethodRecognizer::kExternalUint8ArrayGetIndexed:
- return kExternalTypedDataUint8ArrayCid;
-
- case MethodRecognizer::kExternalUint8ClampedArrayGetIndexed:
- return kExternalTypedDataUint8ClampedArrayCid;
-
- case MethodRecognizer::kInt16ArrayGetIndexed:
- return kTypedDataInt16ArrayCid;
-
- case MethodRecognizer::kUint16ArrayGetIndexed:
- return kTypedDataUint16ArrayCid;
-
- case MethodRecognizer::kInt32ArrayGetIndexed:
- return kTypedDataInt32ArrayCid;
-
- case MethodRecognizer::kUint32ArrayGetIndexed:
- return kTypedDataUint32ArrayCid;
-
- case MethodRecognizer::kFloat32x4ArrayGetIndexed:
- return kTypedDataFloat32x4ArrayCid;
-
- default:
- break;
- }
- return kIllegalCid;
+ *last = new StoreIndexedInstr(new Value(array),
+ new Value(index),
+ new Value(stored_value),
+ needs_store_barrier,
+ index_scale,
+ array_cid,
+ call->deopt_id());
+ flow_graph()->AppendTo(cursor,
+ *last,
+ call->env(),
+ Definition::kEffect);
+ return true;
}
bool FlowGraphOptimizer::TryInlineRecognizedMethod(const Function& target,
Instruction* call,
+ intptr_t token_pos,
const ICData& ic_data,
TargetEntryInstr** entry,
Definition** last) {
+ ICData& value_check = ICData::ZoneHandle();
MethodRecognizer::Kind kind = MethodRecognizer::RecognizeKind(target);
switch (kind) {
+ // Recognized [] operators.
case MethodRecognizer::kImmutableArrayGetIndexed:
case MethodRecognizer::kObjectArrayGetIndexed:
case MethodRecognizer::kGrowableArrayGetIndexed:
@@ -1067,91 +1017,152 @@
case MethodRecognizer::kExternalUint8ClampedArrayGetIndexed:
case MethodRecognizer::kInt16ArrayGetIndexed:
case MethodRecognizer::kUint16ArrayGetIndexed:
- return TryInlineGetIndexed(kind, call, ic_data, entry, last);
+ return InlineGetIndexed(kind, call, ic_data, entry, last);
case MethodRecognizer::kFloat32x4ArrayGetIndexed:
if (!ShouldInlineSimd()) return false;
- return TryInlineGetIndexed(kind, call, ic_data, entry, last);
+ return InlineGetIndexed(kind, call, ic_data, entry, last);
case MethodRecognizer::kInt32ArrayGetIndexed:
case MethodRecognizer::kUint32ArrayGetIndexed:
if (!CanUnboxInt32()) return false;
- return TryInlineGetIndexed(kind, call, ic_data, entry, last);
+ return InlineGetIndexed(kind, call, ic_data, entry, last);
+
+ // Recognized []= operators.
+ case MethodRecognizer::kObjectArraySetIndexed:
+ case MethodRecognizer::kGrowableArraySetIndexed:
+ if (ArgIsAlways(kSmiCid, ic_data, 2)) {
+ value_check = ic_data.AsUnaryClassChecksForArgNr(2);
+ }
+ return InlineSetIndexed(kind, target, call, token_pos,
+ &ic_data, value_check, entry, last);
+ case MethodRecognizer::kInt8ArraySetIndexed:
+ case MethodRecognizer::kUint8ArraySetIndexed:
+ case MethodRecognizer::kUint8ClampedArraySetIndexed:
+ case MethodRecognizer::kExternalUint8ArraySetIndexed:
+ case MethodRecognizer::kExternalUint8ClampedArraySetIndexed:
+ case MethodRecognizer::kInt16ArraySetIndexed:
+ case MethodRecognizer::kUint16ArraySetIndexed:
+ if (!ArgIsAlways(kSmiCid, ic_data, 2)) return false;
+ value_check = ic_data.AsUnaryClassChecksForArgNr(2);
+ return InlineSetIndexed(kind, target, call, token_pos,
+ &ic_data, value_check, entry, last);
+ case MethodRecognizer::kInt32ArraySetIndexed:
+ case MethodRecognizer::kUint32ArraySetIndexed:
+ if (!CanUnboxInt32()) return false;
+ // Check that value is always smi or mint, if the platform has unboxed
+ // mints (ia32 with at least SSE 4.1).
+ value_check = ic_data.AsUnaryClassChecksForArgNr(2);
+ if (FlowGraphCompiler::SupportsUnboxedMints()) {
+ if (!HasOnlySmiOrMint(value_check)) {
+ return false;
+ }
+ } else if (!HasOnlyOneSmi(value_check)) {
+ return false;
+ }
+ return InlineSetIndexed(kind, target, call, token_pos,
+ &ic_data, value_check, entry, last);
+ case MethodRecognizer::kFloat32ArraySetIndexed:
+ case MethodRecognizer::kFloat64ArraySetIndexed:
+ // Check that value is always double.
+ if (!ArgIsAlways(kDoubleCid, ic_data, 2)) return false;
+ value_check = ic_data.AsUnaryClassChecksForArgNr(2);
+ return InlineSetIndexed(kind, target, call, token_pos,
+ &ic_data, value_check, entry, last);
+ case MethodRecognizer::kFloat32x4ArraySetIndexed:
+ if (!ShouldInlineSimd()) return false;
+ // Check that value is always a Float32x4.
+ if (!ArgIsAlways(kFloat32x4Cid, ic_data, 2)) return false;
+ value_check = ic_data.AsUnaryClassChecksForArgNr(2);
+ return InlineSetIndexed(kind, target, call, token_pos,
+ &ic_data, value_check, entry, last);
default:
return false;
}
}
-bool FlowGraphOptimizer::TryInlineGetIndexed(MethodRecognizer::Kind kind,
- Instruction* call,
- const ICData& ic_data,
- TargetEntryInstr** entry,
- Definition** last) {
- intptr_t array_cid = MethodKindToCid(kind);
- ASSERT(array_cid != kIllegalCid);
-
- // Insert index smi checks and attach a copy of the
- // original environment because the operation can still deoptimize.
- Definition* array = call->ArgumentAt(0);
- Definition* index = call->ArgumentAt(1);
- *entry = new TargetEntryInstr(flow_graph()->allocate_block_id(),
- call->GetBlock()->try_index());
- (*entry)->InheritDeoptTarget(call);
-
- Instruction* cursor = *entry;
- cursor = flow_graph()->AppendTo(cursor,
- new CheckSmiInstr(new Value(index),
- call->deopt_id()),
- call->env(),
- Definition::kEffect);
+intptr_t FlowGraphOptimizer::PrepareInlineIndexedOp(Instruction* call,
+ intptr_t array_cid,
+ Definition** array,
+ Definition* index,
+ Instruction** cursor) {
+ // Insert index smi check.
+ *cursor = flow_graph()->AppendTo(*cursor,
+ new CheckSmiInstr(new Value(index),
+ call->deopt_id()),
+ call->env(),
+ Definition::kEffect);
// Insert array length load and bounds check.
const bool is_immutable =
CheckArrayBoundInstr::IsFixedLengthArrayType(array_cid);
LoadFieldInstr* length =
- new LoadFieldInstr(new Value(array),
+ new LoadFieldInstr(new Value(*array),
CheckArrayBoundInstr::LengthOffsetFor(array_cid),
Type::ZoneHandle(Type::SmiType()),
is_immutable);
length->set_result_cid(kSmiCid);
length->set_recognized_kind(
LoadFieldInstr::RecognizedKindFromArrayCid(array_cid));
- cursor = flow_graph()->AppendTo(cursor,
- length,
- NULL,
- Definition::kValue);
+ *cursor = flow_graph()->AppendTo(*cursor,
+ length,
+ NULL,
+ Definition::kValue);
- cursor = flow_graph()->AppendTo(cursor,
- new CheckArrayBoundInstr(
- new Value(length),
- new Value(index),
- call->deopt_id()),
- call->env(),
- Definition::kEffect);
+ *cursor = flow_graph()->AppendTo(*cursor,
+ new CheckArrayBoundInstr(
+ new Value(length),
+ new Value(index),
+ call->deopt_id()),
+ call->env(),
+ Definition::kEffect);
if (array_cid == kGrowableObjectArrayCid) {
// Insert data elements load.
LoadFieldInstr* elements =
- new LoadFieldInstr(new Value(array),
+ new LoadFieldInstr(new Value(*array),
GrowableObjectArray::data_offset(),
Type::ZoneHandle(Type::DynamicType()));
elements->set_result_cid(kArrayCid);
- cursor = flow_graph()->AppendTo(cursor,
- elements,
- NULL,
- Definition::kValue);
+ *cursor = flow_graph()->AppendTo(*cursor,
+ elements,
+ NULL,
+ Definition::kValue);
// Load from the data from backing store which is a fixed-length array.
- array = elements;
+ *array = elements;
array_cid = kArrayCid;
} else if (RawObject::IsExternalTypedDataClassId(array_cid)) {
LoadUntaggedInstr* elements =
- new LoadUntaggedInstr(new Value(array),
+ new LoadUntaggedInstr(new Value(*array),
ExternalTypedData::data_offset());
- cursor = flow_graph()->AppendTo(cursor,
- elements,
- NULL,
- Definition::kValue);
- array = elements;
+ *cursor = flow_graph()->AppendTo(*cursor,
+ elements,
+ NULL,
+ Definition::kValue);
+ *array = elements;
}
+ return array_cid;
+}
+
+bool FlowGraphOptimizer::InlineGetIndexed(MethodRecognizer::Kind kind,
+ Instruction* call,
+ const ICData& ic_data,
+ TargetEntryInstr** entry,
+ Definition** last) {
+ intptr_t array_cid = MethodKindToCid(kind);
+ ASSERT(array_cid != kIllegalCid);
+
+ Definition* array = call->ArgumentAt(0);
+ Definition* index = call->ArgumentAt(1);
+ *entry = new TargetEntryInstr(flow_graph()->allocate_block_id(),
+ call->GetBlock()->try_index());
+ (*entry)->InheritDeoptTarget(call);
+ Instruction* cursor = *entry;
+
+ array_cid = PrepareInlineIndexedOp(call,
+ array_cid,
+ &array,
+ index,
+ &cursor);
intptr_t deopt_id = Isolate::kNoDeoptId;
if ((array_cid == kTypedDataInt32ArrayCid) ||
@@ -1189,6 +1200,7 @@
Definition* last;
if (!TryInlineRecognizedMethod(target,
call,
+ call->token_pos(),
*call->ic_data(),
&entry, &last)) {
return false;
@@ -2963,7 +2975,7 @@
AddReceiverCheck(instr);
}
StoreBarrierType needs_store_barrier = kEmitStoreBarrier;
- if (ArgIsAlwaysSmi(*instr->ic_data(), 1)) {
+ if (ArgIsAlways(kSmiCid, *instr->ic_data(), 1)) {
InsertBefore(instr,
new CheckSmiInstr(new Value(instr->ArgumentAt(1)),
instr->deopt_id()),
diff --git a/runtime/vm/flow_graph_optimizer.h b/runtime/vm/flow_graph_optimizer.h
index 1879186..ad3ab68 100644
--- a/runtime/vm/flow_graph_optimizer.h
+++ b/runtime/vm/flow_graph_optimizer.h
@@ -46,6 +46,7 @@
bool TryInlineRecognizedMethod(const Function& target,
Instruction* call,
+ intptr_t token_pos,
const ICData& ic_data,
TargetEntryInstr** entry,
Definition** last);
@@ -72,20 +73,27 @@
void SpecializePolymorphicInstanceCall(PolymorphicInstanceCallInstr* call);
- intptr_t PrepareIndexedOp(InstanceCallInstr* call,
- intptr_t class_id,
- Definition** array,
- Definition** index);
bool TryReplaceWithStoreIndexed(InstanceCallInstr* call);
- void BuildStoreIndexed(InstanceCallInstr* call,
- const ICData& value_check,
- intptr_t class_id);
+ bool InlineSetIndexed(MethodRecognizer::Kind kind,
+ const Function& target,
+ Instruction* call,
+ intptr_t token_pos,
+ const ICData* ic_data,
+ const ICData& value_check,
+ TargetEntryInstr** entry,
+ Definition** last);
bool TryReplaceWithLoadIndexed(InstanceCallInstr* call);
- bool TryInlineGetIndexed(MethodRecognizer::Kind kind,
- Instruction* call,
- const ICData& ic_data,
- TargetEntryInstr** entry,
- Definition** last);
+ bool InlineGetIndexed(MethodRecognizer::Kind kind,
+ Instruction* call,
+ const ICData& ic_data,
+ TargetEntryInstr** entry,
+ Definition** last);
+ intptr_t PrepareInlineIndexedOp(Instruction* call,
+ intptr_t array_cid,
+ Definition** array,
+ Definition* index,
+ Instruction** cursor);
+
bool TryReplaceWithBinaryOp(InstanceCallInstr* call, Token::Kind op_kind);
bool TryReplaceWithUnaryOp(InstanceCallInstr* call, Token::Kind op_kind);
@@ -130,6 +138,9 @@
intptr_t deopt_id,
Environment* deopt_environment,
Instruction* insert_before);
+ Instruction* GetCheckClass(Definition* to_check,
+ const ICData& unary_checks,
+ intptr_t deopt_id);
// Insert a Smi check if needed.
void AddCheckSmi(Definition* to_check,
diff --git a/runtime/vm/intermediate_language.cc b/runtime/vm/intermediate_language.cc
index 50c4930..a75ba71 100644
--- a/runtime/vm/intermediate_language.cc
+++ b/runtime/vm/intermediate_language.cc
@@ -1429,7 +1429,16 @@
TypeArguments::Cast(constant_type_args->value());
const AbstractType& new_dst_type = AbstractType::Handle(
dst_type().InstantiateFrom(instantiator_type_args, NULL));
+ // If dst_type is instantiated to dynamic or Object, skip the test.
+ if (!new_dst_type.IsMalformed() && !new_dst_type.IsMalbounded() &&
+ (new_dst_type.IsDynamicType() || new_dst_type.IsObjectType())) {
+ return value()->definition();
+ }
set_dst_type(AbstractType::ZoneHandle(new_dst_type.Canonicalize()));
+ if (FLAG_eliminate_type_checks &&
+ value()->Type()->IsAssignableTo(dst_type())) {
+ return value()->definition();
+ }
ConstantInstr* null_constant = flow_graph->constant_null();
instantiator_type_arguments()->BindTo(null_constant);
}
diff --git a/runtime/vm/intermediate_language.h b/runtime/vm/intermediate_language.h
index 35ca39c..e7cf253 100644
--- a/runtime/vm/intermediate_language.h
+++ b/runtime/vm/intermediate_language.h
@@ -136,21 +136,36 @@
V(_Uint32x4, withFlagZ, Uint32x4WithFlagZ, 1714792414) \
V(_Uint32x4, withFlagW, Uint32x4WithFlagW, 1516924162) \
V(_List, [], ObjectArrayGetIndexed, 1079829188) \
+ V(_List, []=, ObjectArraySetIndexed, 748954698) \
V(_ImmutableList, [], ImmutableArrayGetIndexed, 25983597) \
V(_GrowableList, [], GrowableArrayGetIndexed, 1686777561) \
+ V(_GrowableList, []=, GrowableArraySetIndexed, 327404102) \
V(_Float32Array, [], Float32ArrayGetIndexed, 1225286513) \
+ V(_Float32Array, []=, Float32ArraySetIndexed, 1155155195) \
V(_Float64Array, [], Float64ArrayGetIndexed, 871118335) \
+ V(_Float64Array, []=, Float64ArraySetIndexed, 214271306) \
V(_Int8Array, [], Int8ArrayGetIndexed, 199925538) \
+ V(_Int8Array, []=, Int8ArraySetIndexed, 25452746) \
V(_Uint8Array, [], Uint8ArrayGetIndexed, 502448555) \
+ V(_Uint8Array, []=, Uint8ArraySetIndexed, 182237960) \
V(_Uint8ClampedArray, [], Uint8ClampedArrayGetIndexed, 1292893603) \
+ V(_Uint8ClampedArray, []=, Uint8ClampedArraySetIndexed, 670971404) \
V(_ExternalUint8Array, [], ExternalUint8ArrayGetIndexed, 1831383216) \
+ V(_ExternalUint8Array, []=, ExternalUint8ArraySetIndexed, 1660673499) \
V(_ExternalUint8ClampedArray, [], ExternalUint8ClampedArrayGetIndexed, \
1831906095) \
+ V(_ExternalUint8ClampedArray, []=, ExternalUint8ClampedArraySetIndexed, \
+ 19235519) \
V(_Int16Array, [], Int16ArrayGetIndexed, 1191799443) \
+ V(_Int16Array, []=, Int16ArraySetIndexed, 1182335435) \
V(_Uint16Array, [], Uint16ArrayGetIndexed, 814177144) \
+ V(_Uint16Array, []=, Uint16ArraySetIndexed, 663508528) \
V(_Int32Array, [], Int32ArrayGetIndexed, 787321640) \
+ V(_Int32Array, []=, Int32ArraySetIndexed, 1515238594) \
V(_Uint32Array, [], Uint32ArrayGetIndexed, 1421922726) \
+ V(_Uint32Array, []=, Uint32ArraySetIndexed, 1980947178) \
V(_Float32x4Array, [], Float32x4ArrayGetIndexed, 1901126825) \
+ V(_Float32x4Array, []=, Float32x4ArraySetIndexed, 1419416331) \
// A list of core function that should always be inlined.
@@ -4075,6 +4090,7 @@
immutable_(immutable),
recognized_kind_(MethodRecognizer::kUnknown),
field_(NULL) {
+ ASSERT(offset_in_bytes >= 0);
ASSERT(type.IsZoneHandle()); // May be null if field is not an instance.
SetInputAt(0, instance);
}
diff --git a/runtime/vm/isolate.cc b/runtime/vm/isolate.cc
index 0e6ad03..d8ab9a5 100644
--- a/runtime/vm/isolate.cc
+++ b/runtime/vm/isolate.cc
@@ -680,9 +680,6 @@
api_state()->weak_persistent_handles().VisitHandles(&visitor);
CompilerStats::Print();
- // TODO(asiva): Move this code to Dart::Cleanup when we have that method
- // as the cleanup for Dart::InitOnce.
- CodeObservers::DeleteAll();
if (FLAG_trace_isolates) {
heap()->PrintSizes();
megamorphic_cache_table()->PrintSizes();
diff --git a/runtime/vm/parser.cc b/runtime/vm/parser.cc
index 22ec97e..5f805b2 100644
--- a/runtime/vm/parser.cc
+++ b/runtime/vm/parser.cc
@@ -3317,6 +3317,9 @@
if (field->has_factory) {
ErrorMsg("keyword 'factory' not allowed in field declaration");
}
+ if (!field->has_static && field->has_const) {
+ ErrorMsg(field->name_pos, "instance field may not be 'const'");
+ }
if (members->FieldNameExists(*field->name, !field->has_final)) {
ErrorMsg(field->name_pos,
"field or method '%s' already defined", field->name->ToCString());
diff --git a/sdk/lib/_collection_dev/collection_dev.dart b/sdk/lib/_collection_dev/collection_dev.dart
index 79ca515..175fc01 100644
--- a/sdk/lib/_collection_dev/collection_dev.dart
+++ b/sdk/lib/_collection_dev/collection_dev.dart
@@ -8,6 +8,7 @@
import 'dart:core' hide Symbol;
import 'dart:core' as core;
+import 'dart:math' show Random;
part 'arrays.dart';
part 'iterable.dart';
diff --git a/sdk/lib/_collection_dev/iterable.dart b/sdk/lib/_collection_dev/iterable.dart
index 9e7b990..5001fe3 100644
--- a/sdk/lib/_collection_dev/iterable.dart
+++ b/sdk/lib/_collection_dev/iterable.dart
@@ -22,8 +22,13 @@
// sdk/lib/core/regexp.dart
// TODO(floitsch): also used in dart:async until end of September for
// deprecation of runZonedExperimental.
+// TODO(floitsch): also used in dart:json and dart:utf until middle of October
+// for deprecation of json and utf libraries.
-const deprecated = 0;
+// We use a random string constant to avoid it clashing with other constants.
+// This is, because we have a test that verifies that no metadata is included
+// in the output, when no mirrors need them.
+const deprecated = "qB2n4PYM";
/**
* An [Iterable] for classes that have efficient [length] and [elementAt].
@@ -953,6 +958,18 @@
Sort.sort(list, compare);
}
+ static void shuffleList(List list) {
+ Random random = new Random();
+ int length = list.length;
+ while (length > 1) {
+ int pos = random.nextInt(length);
+ length -= 1;
+ var tmp = list[length];
+ list[length] = list[pos];
+ list[pos] = tmp;
+ }
+ }
+
static int indexOfList(List list, var element, int start) {
return Arrays.indexOf(list, element, start, list.length);
}
diff --git a/sdk/lib/_collection_dev/list.dart b/sdk/lib/_collection_dev/list.dart
index f5db3bb..6acc5d2 100644
--- a/sdk/lib/_collection_dev/list.dart
+++ b/sdk/lib/_collection_dev/list.dart
@@ -140,6 +140,11 @@
"Cannot modify an unmodifiable list");
}
+ void shuffle() {
+ throw new UnsupportedError(
+ "Cannot modify an unmodifiable list");
+ }
+
void clear() {
throw new UnsupportedError(
"Cannot clear an unmodifiable list");
diff --git a/sdk/lib/_internal/compiler/implementation/compiler.dart b/sdk/lib/_internal/compiler/implementation/compiler.dart
index 6f673a3..303a467 100644
--- a/sdk/lib/_internal/compiler/implementation/compiler.dart
+++ b/sdk/lib/_internal/compiler/implementation/compiler.dart
@@ -731,7 +731,9 @@
if (node == CURRENT_ELEMENT_SPANNABLE) {
node = currentElement;
}
- if (node is Node) {
+ if (node is SourceSpan) {
+ return node;
+ } else if (node is Node) {
return spanFromNode(node, uri);
} else if (node is Token) {
return spanFromTokens(node, node, uri);
@@ -1530,7 +1532,7 @@
}
}
-class SourceSpan {
+class SourceSpan implements Spannable {
final Uri uri;
final int begin;
final int end;
diff --git a/sdk/lib/_internal/compiler/implementation/dart_types.dart b/sdk/lib/_internal/compiler/implementation/dart_types.dart
index f70517e..9fcd6c3 100644
--- a/sdk/lib/_internal/compiler/implementation/dart_types.dart
+++ b/sdk/lib/_internal/compiler/implementation/dart_types.dart
@@ -71,16 +71,6 @@
DartType unalias(Compiler compiler);
/**
- * Finds the method, field or property named [name] declared or inherited
- * on this type.
- *
- * If [isSetter] is [:true:] the member is interpreted as a setter access.
- */
- // TODO(johnniwinther): Implement this for [TypeVariableType], [FunctionType],
- // and [TypedefType].
- Member lookupMember(SourceString name, {bool isSetter: false}) => null;
-
- /**
* If this type is malformed or a generic type created with the wrong number
* of type arguments then [userProvidedBadType] holds the bad type provided
* by the user.
diff --git a/sdk/lib/_internal/compiler/implementation/elements/elements.dart b/sdk/lib/_internal/compiler/implementation/elements/elements.dart
index c09dfb3..d0e370e 100644
--- a/sdk/lib/_internal/compiler/implementation/elements/elements.dart
+++ b/sdk/lib/_internal/compiler/implementation/elements/elements.dart
@@ -117,6 +117,8 @@
static const ElementKind AMBIGUOUS =
const ElementKind('ambiguous', ElementCategory.NONE);
+ static const ElementKind WARN_ON_USE =
+ const ElementKind('warn_on_use', ElementCategory.NONE);
static const ElementKind ERROR =
const ElementKind('error', ElementCategory.NONE);
@@ -203,6 +205,7 @@
bool isLibrary();
bool isErroneous();
bool isAmbiguous();
+ bool isWarnOnUse();
bool isTopLevel();
bool isAssignable();
@@ -261,6 +264,17 @@
}
static bool isErroneousElement(Element e) => e != null && e.isErroneous();
+ /// Unwraps [element] reporting any warnings attached to it, if any.
+ static Element unwrap(Element element,
+ DiagnosticListener listener,
+ Spannable spannable) {
+ if (element != null && element.isWarnOnUse()) {
+ WarnOnUseElement wrappedElement = element;
+ element = wrappedElement.unwrap(listener, spannable);
+ }
+ return element;
+ }
+
static bool isClass(Element e) => e != null && e.kind == ElementKind.CLASS;
static bool isTypedef(Element e) {
return e != null && e.kind == ElementKind.TYPEDEF;
@@ -335,6 +349,7 @@
static bool isNativeOrExtendsNative(ClassElement element) {
if (element == null) return false;
if (element.isNative()) return true;
+ assert(element.resolutionState == STATE_DONE);
return isNativeOrExtendsNative(element.superclass);
}
@@ -583,6 +598,17 @@
Map get messageArguments;
}
+/// An [Element] whose usage should cause a warning.
+abstract class WarnOnUseElement extends Element {
+ /// The element whose usage cause a warning.
+ Element get wrappedElement;
+
+ /// Reports the attached warning and returns the wrapped element.
+ /// [usageSpannable] is used to report messages on the reference of
+ /// [wrappedElement].
+ Element unwrap(DiagnosticListener listener, Spannable usageSpannable);
+}
+
abstract class AmbiguousElement extends Element {
DualKind get messageKind;
Map get messageArguments;
diff --git a/sdk/lib/_internal/compiler/implementation/elements/modelx.dart b/sdk/lib/_internal/compiler/implementation/elements/modelx.dart
index 394d4e4..e74bd0d 100644
--- a/sdk/lib/_internal/compiler/implementation/elements/modelx.dart
+++ b/sdk/lib/_internal/compiler/implementation/elements/modelx.dart
@@ -98,6 +98,9 @@
/** See [AmbiguousElement] for documentation. */
bool isAmbiguous() => false;
+ /** See [WarnOnUseElement] for documentation. */
+ bool isWarnOnUse() => false;
+
/**
* Is [:true:] if this element has a corresponding patch.
*
@@ -350,6 +353,66 @@
}
}
+/// A message attached to a [WarnOnUseElementX].
+class WrappedMessage {
+ /// The message position. If [:null:] the position of the reference to the
+ /// [WarnOnUseElementX] is used.
+ final Spannable spannable;
+
+ /**
+ * The message to report on resolving a wrapped element.
+ */
+ final MessageKind messageKind;
+
+ /**
+ * The message arguments to report on resolving a wrapped element.
+ */
+ final Map messageArguments;
+
+ WrappedMessage(this.spannable, this.messageKind, this.messageArguments);
+}
+
+/**
+ * An [Element] whose reference should cause one or more warnings.
+ */
+class WarnOnUseElementX extends ElementX implements WarnOnUseElement {
+ /// Warning to report on resolving this element.
+ final WrappedMessage warning;
+
+ /// Info to report on resolving this element.
+ final WrappedMessage info;
+
+ /// The element whose usage cause a warning.
+ final Element wrappedElement;
+
+ WarnOnUseElementX(WrappedMessage this.warning, WrappedMessage this.info,
+ Element enclosingElement, Element wrappedElement)
+ : this.wrappedElement = wrappedElement,
+ super(wrappedElement.name, ElementKind.WARN_ON_USE, enclosingElement);
+
+ bool isWarnOnUse() => true;
+
+ Element unwrap(DiagnosticListener listener, Spannable usageSpannable) {
+ var unwrapped = wrappedElement;
+ if (warning != null) {
+ Spannable spannable = warning.spannable;
+ if (spannable == null) spannable = usageSpannable;
+ listener.reportWarningCode(
+ spannable, warning.messageKind, warning.messageArguments);
+ }
+ if (info != null) {
+ Spannable spannable = info.spannable;
+ if (spannable == null) spannable = usageSpannable;
+ listener.reportInfo(
+ spannable, info.messageKind, info.messageArguments);
+ }
+ if (unwrapped.isWarnOnUse()) {
+ unwrapped = unwrapped.unwrap(listener, usageSpannable);
+ }
+ return unwrapped;
+ }
+}
+
/**
* An ambiguous element represents multiple elements accessible by the same name.
*
@@ -404,7 +467,7 @@
? MessageKind.AMBIGUOUS_REEXPORT : MessageKind.AMBIGUOUS_LOCATION;
LibraryElementX importer = context.getLibrary();
for (Element element in ambiguousElements) {
- var arguments = {'element': element};
+ var arguments = {'name': element.name};
listener.reportInfo(element, code, arguments);
Link<Import> importers = importer.importers[element];
listener.withCurrentElement(importer, () {
@@ -667,8 +730,7 @@
* Adds [element] to the import scope of this library.
*
* If an element by the same name is already in the imported scope, an
- * [ErroneousElement] will be put in the imported scope, allowing for the
- * detection of ambiguous uses of imported names.
+ * [ErroneousElement] will be put in the imported scope, allowing for detection of ambiguous uses of imported names.
*/
void addImport(Element element, Import import, DiagnosticListener listener) {
importers[element] =
@@ -676,31 +738,42 @@
.prepend(import);
SourceString name = element.name;
Element existing = importScope.putIfAbsent(name, () => element);
+
+ Element createWarnOnUseElement(Spannable spannable,
+ MessageKind messageKind,
+ Element hidingElement,
+ Element hiddenElement) {
+ Uri hiddenUri = hiddenElement.getLibrary().canonicalUri;
+ Uri hidingUri = hidingElement.getLibrary().canonicalUri;
+ return new WarnOnUseElementX(
+ new WrappedMessage(
+ null, // Report on reference to [hidingElement].
+ messageKind,
+ {'name': name, 'hiddenUri': hiddenUri, 'hidingUri': hidingUri}),
+ new WrappedMessage(
+ listener.spanFromSpannable(spannable),
+ MessageKind.IMPORTED_HERE,
+ {'name': name}),
+ this, hidingElement);
+ }
+
if (existing != element) {
- // TODO(johnniwinther): Only emit these warnings if [element] is used.
if (existing.getLibrary().isPlatformLibrary &&
!element.getLibrary().isPlatformLibrary) {
// [existing] is implicitly hidden.
- importScope[name] = element;
- listener.reportWarningCode(import, MessageKind.HIDDEN_IMPORT,
- {'name': name,
- 'hiddenUri': existing.getLibrary().canonicalUri,
- 'hidingUri': element.getLibrary().canonicalUri});
+ importScope[name] = createWarnOnUseElement(
+ import, MessageKind.HIDDEN_IMPORT, element, existing);
} else if (!existing.getLibrary().isPlatformLibrary &&
element.getLibrary().isPlatformLibrary) {
// [element] is implicitly hidden.
if (import == null) {
// [element] is imported implicitly (probably through dart:core).
- listener.reportWarningCode(importers[existing].head,
- MessageKind.HIDDEN_IMPLICIT_IMPORT,
- {'name': name,
- 'hiddenUri': element.getLibrary().canonicalUri,
- 'hidingUri': existing.getLibrary().canonicalUri});
+ importScope[name] = createWarnOnUseElement(
+ importers[existing].head, MessageKind.HIDDEN_IMPLICIT_IMPORT,
+ existing, element);
} else {
- listener.reportWarningCode(import, MessageKind.HIDDEN_IMPORT,
- {'name': name,
- 'hiddenUri': element.getLibrary().canonicalUri,
- 'hidingUri': existing.getLibrary().canonicalUri});
+ importScope[name] = createWarnOnUseElement(
+ import, MessageKind.HIDDEN_IMPORT, existing, element);
}
} else {
// TODO(johnniwinther): Provide access to the import tags from which
diff --git a/sdk/lib/_internal/compiler/implementation/js_backend/backend.dart b/sdk/lib/_internal/compiler/implementation/js_backend/backend.dart
index 754e5aa..a60feea 100644
--- a/sdk/lib/_internal/compiler/implementation/js_backend/backend.dart
+++ b/sdk/lib/_internal/compiler/implementation/js_backend/backend.dart
@@ -477,9 +477,11 @@
}
bool isInterceptedMethod(Element element) {
- return element.isInstanceMember()
- && !element.isGenerativeConstructorBody()
- && interceptedElements[element.name] != null;
+ if (!element.isInstanceMember()) return false;
+ if (element.isGenerativeConstructorBody()) {
+ return Elements.isNativeOrExtendsNative(element.getEnclosingClass());
+ }
+ return interceptedElements[element.name] != null;
}
bool fieldHasInterceptedGetter(Element element) {
@@ -952,6 +954,30 @@
if (element.isTypedef()) {
typedefTypeLiterals.add(element);
}
+ if (element.isClass()) {
+ // TODO(sra): Can we register via a type parameter?
+ registerEscapingConstructorsOfClass(element, enqueuer);
+ }
+ }
+
+ void registerEscapingConstructorsOfClass(ClassElement classElement,
+ Enqueuer enqueuer) {
+ // Web component classes have constructors that are escaped to the host
+ // environment.
+ // TODO(13835): Defer registering generative constructors until the helper
+ // functions that fetch the constructors is seen. These functions are
+ // called by document.register.
+ classElement.ensureResolved(compiler);
+ if (Elements.isNativeOrExtendsNative(classElement)) {
+ registerGenerativeConstructors(ClassElement enclosing, Element member) {
+ if (member.isGenerativeConstructor()) {
+ enqueuer.registerStaticUse(member);
+ }
+ }
+ classElement.forEachMember(registerGenerativeConstructors,
+ includeBackendMembers: false,
+ includeSuperAndInjectedMembers: false);
+ }
}
void registerStackTraceInCatch(TreeElements elements) {
diff --git a/sdk/lib/_internal/compiler/implementation/js_backend/js_backend.dart b/sdk/lib/_internal/compiler/implementation/js_backend/js_backend.dart
index b7cf4f2..de6a0aa 100644
--- a/sdk/lib/_internal/compiler/implementation/js_backend/js_backend.dart
+++ b/sdk/lib/_internal/compiler/implementation/js_backend/js_backend.dart
@@ -8,26 +8,21 @@
import 'dart:collection' show LinkedHashMap, Queue;
import '../closure.dart';
-import '../../compiler.dart' as api;
import '../elements/elements.dart';
-import '../elements/modelx.dart' show FunctionElementX;
-import '../js_emitter/js_emitter.dart' show Emitter, CodeEmitterTask, ClassBuilder;
+import '../js_emitter/js_emitter.dart'
+ show Emitter, CodeEmitterTask, ClassBuilder;
-// TODO(ahe): There seems to be a bug in the VM, so we have to hide "js".
-import '../dart2jslib.dart' hide Selector, TypedSelector, js;
+import '../dart2jslib.dart';
import '../dart_types.dart';
import '../js/js.dart' as jsAst;
-import '../js/js.dart' show js; // TODO(ahe): VM bug, see above.
+import '../js/js.dart' show js;
import '../native_handler.dart' as native;
-import '../source_file.dart';
-import '../source_map_builder.dart';
-import '../ssa/ssa.dart' hide js; // TODO(ahe): VM bug, see above.
+import '../ssa/ssa.dart';
import '../tree/tree.dart';
import '../types/types.dart';
-import '../universe/universe.dart' hide js; // TODO(ahe): VM bug, see above.
+import '../universe/universe.dart';
import '../util/characters.dart';
import '../util/util.dart';
-import '../util/uri_extras.dart' show relativize;
part 'backend.dart';
part 'constant_emitter.dart';
diff --git a/sdk/lib/_internal/compiler/implementation/js_backend/native_emitter.dart b/sdk/lib/_internal/compiler/implementation/js_backend/native_emitter.dart
index 1f83c5f..db7898d 100644
--- a/sdk/lib/_internal/compiler/implementation/js_backend/native_emitter.dart
+++ b/sdk/lib/_internal/compiler/implementation/js_backend/native_emitter.dart
@@ -187,7 +187,7 @@
Set<ClassElement> neededByConstant =
emitter.interceptorsReferencedFromConstants();
Set<ClassElement> modifiedClasses =
- emitter.classesModifiedByEmitRuntimeTypeSupport();
+ emitter.typeTestEmitter.classesModifiedByEmitRuntimeTypeSupport();
for (ClassElement classElement in preOrder.reversed) {
// Post-order traversal ensures we visit the subclasses before their
@@ -283,7 +283,7 @@
if (!classElement.isNative()) continue;
if (neededClasses.contains(classElement)) {
// Define interceptor class for [classElement].
- emitter.emitClassBuilderWithReflectionData(
+ emitter.classEmitter.emitClassBuilderWithReflectionData(
backend.namer.getNameOfClass(classElement),
classElement, builders[classElement],
emitter.bufferForElement(classElement, mainBuffer));
@@ -341,14 +341,13 @@
String superName = backend.namer.getNameOfClass(superclass);
ClassBuilder builder = new ClassBuilder();
- emitter.emitClassConstructor(classElement, builder, null);
- emitter.emitSuper(superName, builder);
- bool hasFields = emitter.emitFields(
+ emitter.classEmitter.emitClassConstructor(classElement, builder, null);
+ bool hasFields = emitter.classEmitter.emitFields(
classElement, builder, superName, classIsNative: true);
int propertyCount = builder.properties.length;
- emitter.emitClassGettersSetters(classElement, builder);
- emitter.emitInstanceMembers(classElement, builder);
- emitter.emitIsTests(classElement, builder);
+ emitter.classEmitter.emitClassGettersSetters(classElement, builder);
+ emitter.classEmitter.emitInstanceMembers(classElement, builder);
+ emitter.typeTestEmitter.emitIsTests(classElement, builder);
if (!hasFields &&
builder.properties.length == propertyCount &&
@@ -513,7 +512,7 @@
// If the native emitter has been asked to take care of the
// noSuchMethod handlers, we do that now.
if (handleNoSuchMethod) {
- emitter.emitNoSuchMethodHandlers(addProperty);
+ emitter.nsmEmitter.emitNoSuchMethodHandlers(addProperty);
}
}
diff --git a/sdk/lib/_internal/compiler/implementation/js_backend/runtime_types.dart b/sdk/lib/_internal/compiler/implementation/js_backend/runtime_types.dart
index fbb9da7..8f92771 100644
--- a/sdk/lib/_internal/compiler/implementation/js_backend/runtime_types.dart
+++ b/sdk/lib/_internal/compiler/implementation/js_backend/runtime_types.dart
@@ -262,8 +262,8 @@
new Set<DartType>.from(universe.instantiatedTypes);
for (DartType instantiatedType in universe.instantiatedTypes) {
if (instantiatedType.kind == TypeKind.INTERFACE) {
- Member member =
- instantiatedType.lookupMember(Compiler.CALL_OPERATOR_NAME);
+ InterfaceType interface = instantiatedType;
+ Member member = interface.lookupMember(Compiler.CALL_OPERATOR_NAME);
if (member != null) {
instantiatedTypes.add(member.computeType(compiler));
}
diff --git a/sdk/lib/_internal/compiler/implementation/js_emitter/class_emitter.dart b/sdk/lib/_internal/compiler/implementation/js_emitter/class_emitter.dart
new file mode 100644
index 0000000..edf808f
--- /dev/null
+++ b/sdk/lib/_internal/compiler/implementation/js_emitter/class_emitter.dart
@@ -0,0 +1,593 @@
+// 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 dart2js.js_emitter;
+
+class ClassEmitter extends CodeEmitterHelper {
+ /**
+ * Documentation wanted -- johnniwinther
+ *
+ * Invariant: [classElement] must be a declaration element.
+ */
+ void generateClass(ClassElement classElement, CodeBuffer buffer) {
+ final onlyForRti =
+ task.typeTestEmitter.rtiNeededClasses.contains(classElement);
+
+ assert(invariant(classElement, classElement.isDeclaration));
+ assert(invariant(classElement, !classElement.isNative() || onlyForRti));
+
+ task.needsDefineClass = true;
+ String className = namer.getNameOfClass(classElement);
+
+ ClassElement superclass = classElement.superclass;
+ String superName = "";
+ if (superclass != null) {
+ superName = namer.getNameOfClass(superclass);
+ }
+ String runtimeName =
+ namer.getPrimitiveInterceptorRuntimeName(classElement);
+
+ if (classElement.isMixinApplication) {
+ String mixinName = namer.getNameOfClass(computeMixinClass(classElement));
+ superName = '$superName+$mixinName';
+ task.needsMixinSupport = true;
+ }
+
+ ClassBuilder builder = new ClassBuilder();
+ emitClassConstructor(classElement, builder, runtimeName);
+ emitFields(classElement, builder, superName, onlyForRti: onlyForRti);
+ emitClassGettersSetters(classElement, builder);
+ if (!classElement.isMixinApplication) {
+ emitInstanceMembers(classElement, builder);
+ }
+ task.typeTestEmitter.emitIsTests(classElement, builder);
+
+ emitClassBuilderWithReflectionData(
+ className, classElement, builder, buffer);
+ }
+
+ void emitClassConstructor(ClassElement classElement,
+ ClassBuilder builder,
+ String runtimeName) {
+ List<String> fields = <String>[];
+ if (!classElement.isNative()) {
+ visitFields(classElement, false,
+ (Element member,
+ String name,
+ String accessorName,
+ bool needsGetter,
+ bool needsSetter,
+ bool needsCheckedSetter) {
+ fields.add(name);
+ });
+ }
+ String constructorName = namer.getNameOfClass(classElement);
+ task.precompiledFunction.add(new jsAst.FunctionDeclaration(
+ new jsAst.VariableDeclaration(constructorName),
+ js.fun(fields, fields.map(
+ (name) => js('this.$name = $name')).toList())));
+ if (runtimeName == null) {
+ runtimeName = constructorName;
+ }
+ task.precompiledFunction.addAll([
+ js('$constructorName.builtin\$cls = "$runtimeName"'),
+ js.if_('!"name" in $constructorName',
+ js('$constructorName.name = "$constructorName"')),
+ js('\$desc=\$collectedClasses.$constructorName'),
+ js.if_('\$desc instanceof Array', js('\$desc = \$desc[1]')),
+ js('$constructorName.prototype = \$desc'),
+ ]);
+
+ task.precompiledConstructorNames.add(js(constructorName));
+ }
+
+ /// Returns `true` if fields added.
+ bool emitFields(Element element,
+ ClassBuilder builder,
+ String superName,
+ { bool classIsNative: false,
+ bool emitStatics: false,
+ bool onlyForRti: false }) {
+ assert(!emitStatics || !onlyForRti);
+ bool isClass = false;
+ bool isLibrary = false;
+ if (element.isClass()) {
+ isClass = true;
+ } else if (element.isLibrary()) {
+ isLibrary = false;
+ assert(invariant(element, emitStatics));
+ } else {
+ throw new SpannableAssertionFailure(
+ element, 'Must be a ClassElement or a LibraryElement');
+ }
+ StringBuffer buffer = new StringBuffer();
+ if (emitStatics) {
+ assert(invariant(element, superName == null, message: superName));
+ } else {
+ assert(invariant(element, superName != null));
+ String nativeName =
+ namer.getPrimitiveInterceptorRuntimeName(element);
+ if (nativeName != null) {
+ buffer.write('$nativeName/');
+ }
+ buffer.write('$superName;');
+ }
+ int bufferClassLength = buffer.length;
+
+ String separator = '';
+
+ var fieldMetadata = [];
+ bool hasMetadata = false;
+
+ if (!onlyForRti) {
+ visitFields(element, emitStatics,
+ (VariableElement field,
+ String name,
+ String accessorName,
+ bool needsGetter,
+ bool needsSetter,
+ bool needsCheckedSetter) {
+ // Ignore needsCheckedSetter - that is handled below.
+ bool needsAccessor = (needsGetter || needsSetter);
+ // We need to output the fields for non-native classes so we can auto-
+ // generate the constructor. For native classes there are no
+ // constructors, so we don't need the fields unless we are generating
+ // accessors at runtime.
+ if (!classIsNative || needsAccessor) {
+ buffer.write(separator);
+ separator = ',';
+ var metadata = task.buildMetadataFunction(field);
+ if (metadata != null) {
+ hasMetadata = true;
+ } else {
+ metadata = new jsAst.LiteralNull();
+ }
+ fieldMetadata.add(metadata);
+ recordMangledField(field, accessorName, field.name.slowToString());
+ if (!needsAccessor) {
+ // Emit field for constructor generation.
+ assert(!classIsNative);
+ buffer.write(name);
+ } else {
+ // Emit (possibly renaming) field name so we can add accessors at
+ // runtime.
+ buffer.write(accessorName);
+ if (name != accessorName) {
+ buffer.write(':$name');
+ // Only the native classes can have renaming accessors.
+ assert(classIsNative);
+ }
+
+ int getterCode = 0;
+ if (needsGetter) {
+ if (field.isInstanceMember()) {
+ // 01: function() { return this.field; }
+ // 10: function(receiver) { return receiver.field; }
+ // 11: function(receiver) { return this.field; }
+ bool isIntercepted = backend.fieldHasInterceptedGetter(field);
+ getterCode += isIntercepted ? 2 : 0;
+ getterCode += backend.isInterceptorClass(element) ? 0 : 1;
+ // TODO(sra): 'isInterceptorClass' might not be the correct test
+ // for methods forced to use the interceptor convention because
+ // the method's class was elsewhere mixed-in to an interceptor.
+ assert(!field.isInstanceMember() || getterCode != 0);
+ if (isIntercepted) {
+ task.interceptorInvocationNames.add(namer.getterName(field));
+ }
+ } else {
+ getterCode = 1;
+ }
+ }
+ int setterCode = 0;
+ if (needsSetter) {
+ if (field.isInstanceMember()) {
+ // 01: function(value) { this.field = value; }
+ // 10: function(receiver, value) { receiver.field = value; }
+ // 11: function(receiver, value) { this.field = value; }
+ bool isIntercepted = backend.fieldHasInterceptedSetter(field);
+ setterCode += isIntercepted ? 2 : 0;
+ setterCode += backend.isInterceptorClass(element) ? 0 : 1;
+ assert(!field.isInstanceMember() || setterCode != 0);
+ if (isIntercepted) {
+ task.interceptorInvocationNames.add(namer.setterName(field));
+ }
+ } else {
+ setterCode = 1;
+ }
+ }
+ int code = getterCode + (setterCode << 2);
+ if (code == 0) {
+ compiler.reportInternalError(
+ field, 'Internal error: code is 0 ($element/$field)');
+ } else {
+ buffer.write(FIELD_CODE_CHARACTERS[code - FIRST_FIELD_CODE]);
+ }
+ }
+ if (backend.isAccessibleByReflection(field)) {
+ buffer.write(new String.fromCharCode(REFLECTION_MARKER));
+ }
+ }
+ });
+ }
+
+ bool fieldsAdded = buffer.length > bufferClassLength;
+ String compactClassData = buffer.toString();
+ jsAst.Expression classDataNode = js.string(compactClassData);
+ if (hasMetadata) {
+ fieldMetadata.insert(0, classDataNode);
+ classDataNode = new jsAst.ArrayInitializer.from(fieldMetadata);
+ }
+ builder.addProperty('', classDataNode);
+ return fieldsAdded;
+ }
+
+ void emitClassGettersSetters(ClassElement classElement,
+ ClassBuilder builder) {
+
+ visitFields(classElement, false,
+ (VariableElement member,
+ String name,
+ String accessorName,
+ bool needsGetter,
+ bool needsSetter,
+ bool needsCheckedSetter) {
+ compiler.withCurrentElement(member, () {
+ if (needsCheckedSetter) {
+ assert(!needsSetter);
+ generateCheckedSetter(member, name, accessorName, builder);
+ }
+ if (needsGetter) {
+ generateGetter(member, name, accessorName, builder);
+ }
+ if (needsSetter) {
+ generateSetter(member, name, accessorName, builder);
+ }
+ });
+ });
+ }
+
+ /**
+ * Documentation wanted -- johnniwinther
+ *
+ * Invariant: [classElement] must be a declaration element.
+ */
+ void emitInstanceMembers(ClassElement classElement,
+ ClassBuilder builder) {
+ assert(invariant(classElement, classElement.isDeclaration));
+
+ void visitMember(ClassElement enclosing, Element member) {
+ assert(invariant(classElement, member.isDeclaration));
+ if (member.isInstanceMember()) {
+ task.containerBuilder.addMember(member, builder);
+ }
+ }
+
+ classElement.implementation.forEachMember(
+ visitMember,
+ includeBackendMembers: true);
+
+ if (identical(classElement, compiler.objectClass)
+ && compiler.enabledNoSuchMethod) {
+ // Emit the noSuchMethod handlers on the Object prototype now,
+ // so that the code in the dynamicFunction helper can find
+ // them. Note that this helper is invoked before analyzing the
+ // full JS script.
+ if (!task.nativeEmitter.handleNoSuchMethod) {
+ task.nsmEmitter.emitNoSuchMethodHandlers(builder.addProperty);
+ }
+ }
+ }
+
+ void emitClassBuilderWithReflectionData(String className,
+ ClassElement classElement,
+ ClassBuilder builder,
+ CodeBuffer buffer) {
+ var metadata = task.buildMetadataFunction(classElement);
+ if (metadata != null) {
+ builder.addProperty("@", metadata);
+ }
+
+ if (backend.isNeededForReflection(classElement)) {
+ Link typeVars = classElement.typeVariables;
+ List properties = [];
+ for (TypeVariableType typeVar in typeVars) {
+ properties.add(js.string(typeVar.name.slowToString()));
+ properties.add(js.toExpression(task.reifyType(typeVar.element.bound)));
+ }
+
+ ClassElement superclass = classElement.superclass;
+ bool hasSuper = superclass != null;
+ if ((!properties.isEmpty && !hasSuper) ||
+ (hasSuper && superclass.typeVariables != typeVars)) {
+ builder.addProperty('<>', new jsAst.ArrayInitializer.from(properties));
+ }
+ }
+ List<CodeBuffer> classBuffers = task.elementBuffers[classElement];
+ if (classBuffers == null) {
+ classBuffers = [];
+ } else {
+ task.elementBuffers.remove(classElement);
+ }
+ CodeBuffer statics = new CodeBuffer();
+ statics.write('{$n');
+ bool hasStatics = false;
+ ClassBuilder staticsBuilder = new ClassBuilder();
+ if (emitFields(classElement, staticsBuilder, null, emitStatics: true)) {
+ hasStatics = true;
+ statics.write('"":$_');
+ statics.write(
+ jsAst.prettyPrint(staticsBuilder.properties.single.value, compiler));
+ statics.write(',$n');
+ }
+ for (CodeBuffer classBuffer in classBuffers) {
+ // TODO(ahe): What about deferred?
+ if (classBuffer != null) {
+ hasStatics = true;
+ statics.addBuffer(classBuffer);
+ }
+ }
+ statics.write('}$n');
+ if (hasStatics) {
+ builder.addProperty('static', new jsAst.Blob(statics));
+ }
+
+ // TODO(ahe): This method (generateClass) should return a jsAst.Expression.
+ if (!buffer.isEmpty) {
+ buffer.write(',$n$n');
+ }
+ buffer.write('$className:$_');
+ buffer.write(jsAst.prettyPrint(builder.toObjectInitializer(), compiler));
+ String reflectionName = task.getReflectionName(classElement, className);
+ if (reflectionName != null) {
+ List<int> interfaces = <int>[];
+ for (DartType interface in classElement.interfaces) {
+ interfaces.add(task.reifyType(interface));
+ }
+ buffer.write(',$n$n"+$reflectionName": $interfaces');
+ }
+ }
+
+ /**
+ * Calls [addField] for each of the fields of [element].
+ *
+ * [element] must be a [ClassElement] or a [LibraryElement].
+ *
+ * If [element] is a [ClassElement], the static fields of the class are
+ * visited if [visitStatics] is true and the instance fields are visited if
+ * [visitStatics] is false.
+ *
+ * If [element] is a [LibraryElement], [visitStatics] must be true.
+ *
+ * When visiting the instance fields of a class, the fields of its superclass
+ * are also visited if the class is instantiated.
+ *
+ * Invariant: [element] must be a declaration element.
+ */
+ void visitFields(Element element, bool visitStatics, AcceptField f) {
+ assert(invariant(element, element.isDeclaration));
+
+ bool isClass = false;
+ bool isLibrary = false;
+ if (element.isClass()) {
+ isClass = true;
+ } else if (element.isLibrary()) {
+ isLibrary = true;
+ assert(invariant(element, visitStatics));
+ } else {
+ throw new SpannableAssertionFailure(
+ element, 'Expected a ClassElement or a LibraryElement.');
+ }
+
+ // If the class is never instantiated we still need to set it up for
+ // inheritance purposes, but we can simplify its JavaScript constructor.
+ bool isInstantiated =
+ compiler.codegenWorld.instantiatedClasses.contains(element);
+
+ void visitField(Element holder, VariableElement field) {
+ assert(invariant(element, field.isDeclaration));
+ SourceString name = field.name;
+
+ // Keep track of whether or not we're dealing with a field mixin
+ // into a native class.
+ bool isMixinNativeField =
+ isClass && element.isNative() && holder.isMixinApplication;
+
+ // See if we can dynamically create getters and setters.
+ // We can only generate getters and setters for [element] since
+ // the fields of super classes could be overwritten with getters or
+ // setters.
+ bool needsGetter = false;
+ bool needsSetter = false;
+ // We need to name shadowed fields differently, so they don't clash with
+ // the non-shadowed field.
+ bool isShadowed = false;
+ if (isLibrary || isMixinNativeField || holder == element) {
+ needsGetter = fieldNeedsGetter(field);
+ needsSetter = fieldNeedsSetter(field);
+ } else {
+ ClassElement cls = element;
+ isShadowed = cls.isShadowedByField(field);
+ }
+
+ if ((isInstantiated && !holder.isNative())
+ || needsGetter
+ || needsSetter) {
+ String accessorName = isShadowed
+ ? namer.shadowedFieldName(field)
+ : namer.getNameOfField(field);
+ String fieldName = field.hasFixedBackendName()
+ ? field.fixedBackendName()
+ : (isMixinNativeField ? name.slowToString() : accessorName);
+ bool needsCheckedSetter = false;
+ if (compiler.enableTypeAssertions
+ && needsSetter
+ && canGenerateCheckedSetter(field)) {
+ needsCheckedSetter = true;
+ needsSetter = false;
+ }
+ // Getters and setters with suffixes will be generated dynamically.
+ f(field, fieldName, accessorName, needsGetter, needsSetter,
+ needsCheckedSetter);
+ }
+ }
+
+ if (isLibrary) {
+ LibraryElement library = element;
+ library.implementation.forEachLocalMember((Element member) {
+ if (member.isField()) visitField(library, member);
+ });
+ } else if (visitStatics) {
+ ClassElement cls = element;
+ cls.implementation.forEachStaticField(visitField);
+ } else {
+ ClassElement cls = element;
+ // TODO(kasperl): We should make sure to only emit one version of
+ // overridden fields. Right now, we rely on the ordering so the
+ // fields pulled in from mixins are replaced with the fields from
+ // the class definition.
+
+ // If a class is not instantiated then we add the field just so we can
+ // generate the field getter/setter dynamically. Since this is only
+ // allowed on fields that are in [element] we don't need to visit
+ // superclasses for non-instantiated classes.
+ cls.implementation.forEachInstanceField(
+ visitField, includeSuperAndInjectedMembers: isInstantiated);
+ }
+ }
+
+ void recordMangledField(Element member,
+ String accessorName,
+ String memberName) {
+ if (!backend.shouldRetainGetter(member)) return;
+ String previousName;
+ if (member.isInstanceMember()) {
+ previousName = task.mangledFieldNames.putIfAbsent(
+ '${namer.getterPrefix}$accessorName',
+ () => memberName);
+ } else {
+ previousName = task.mangledGlobalFieldNames.putIfAbsent(
+ accessorName,
+ () => memberName);
+ }
+ assert(invariant(member, previousName == memberName,
+ message: '$previousName != ${memberName}'));
+ }
+
+ bool fieldNeedsGetter(VariableElement field) {
+ assert(field.isField());
+ if (fieldAccessNeverThrows(field)) return false;
+ return backend.shouldRetainGetter(field)
+ || compiler.codegenWorld.hasInvokedGetter(field, compiler);
+ }
+
+ bool fieldNeedsSetter(VariableElement field) {
+ assert(field.isField());
+ if (fieldAccessNeverThrows(field)) return false;
+ return (!field.modifiers.isFinalOrConst())
+ && (backend.shouldRetainSetter(field)
+ || compiler.codegenWorld.hasInvokedSetter(field, compiler));
+ }
+
+ // We never access a field in a closure (a captured variable) without knowing
+ // that it is there. Therefore we don't need to use a getter (that will throw
+ // if the getter method is missing), but can always access the field directly.
+ static bool fieldAccessNeverThrows(VariableElement field) {
+ return field is ClosureFieldElement;
+ }
+
+ bool canGenerateCheckedSetter(VariableElement field) {
+ // We never generate accessors for top-level/static fields.
+ if (!field.isInstanceMember()) return false;
+ DartType type = field.computeType(compiler).unalias(compiler);
+ if (type.element.isTypeVariable() ||
+ (type is FunctionType && type.containsTypeVariables) ||
+ type.treatAsDynamic ||
+ type.element == compiler.objectClass) {
+ // TODO(ngeoffray): Support type checks on type parameters.
+ return false;
+ }
+ return true;
+ }
+
+ void generateCheckedSetter(Element member,
+ String fieldName,
+ String accessorName,
+ ClassBuilder builder) {
+ assert(canGenerateCheckedSetter(member));
+ DartType type = member.computeType(compiler);
+ // TODO(ahe): Generate a dynamic type error here.
+ if (type.element.isErroneous()) return;
+ type = type.unalias(compiler);
+ // TODO(11273): Support complex subtype checks.
+ type = type.asRaw();
+ CheckedModeHelper helper =
+ backend.getCheckedModeHelper(type, typeCast: false);
+ FunctionElement helperElement = helper.getElement(compiler);
+ String helperName = namer.isolateAccess(helperElement);
+ List<jsAst.Expression> arguments = <jsAst.Expression>[js('v')];
+ if (helperElement.computeSignature(compiler).parameterCount != 1) {
+ arguments.add(js.string(namer.operatorIsType(type)));
+ }
+
+ String setterName = namer.setterNameFromAccessorName(accessorName);
+ String receiver = backend.isInterceptorClass(member.getEnclosingClass())
+ ? 'receiver' : 'this';
+ List<String> args = backend.isInterceptedMethod(member)
+ ? ['receiver', 'v']
+ : ['v'];
+ builder.addProperty(setterName,
+ js.fun(args,
+ js('$receiver.$fieldName = #', js(helperName)(arguments))));
+ generateReflectionDataForFieldGetterOrSetter(
+ member, setterName, builder, isGetter: false);
+ }
+
+ void generateGetter(Element member, String fieldName, String accessorName,
+ ClassBuilder builder) {
+ String getterName = namer.getterNameFromAccessorName(accessorName);
+ ClassElement cls = member.getEnclosingClass();
+ String className = namer.getNameOfClass(cls);
+ String receiver = backend.isInterceptorClass(cls) ? 'receiver' : 'this';
+ List<String> args = backend.isInterceptedMethod(member) ? ['receiver'] : [];
+ task.precompiledFunction.add(
+ js('$className.prototype.$getterName = #',
+ js.fun(args, js.return_(js('$receiver.$fieldName')))));
+ if (backend.isNeededForReflection(member)) {
+ task.precompiledFunction.add(
+ js('$className.prototype.$getterName.${namer.reflectableField} = 1'));
+ }
+ }
+
+ void generateSetter(Element member, String fieldName, String accessorName,
+ ClassBuilder builder) {
+ String setterName = namer.setterNameFromAccessorName(accessorName);
+ ClassElement cls = member.getEnclosingClass();
+ String className = namer.getNameOfClass(cls);
+ String receiver = backend.isInterceptorClass(cls) ? 'receiver' : 'this';
+ List<String> args =
+ backend.isInterceptedMethod(member) ? ['receiver', 'v'] : ['v'];
+ task.precompiledFunction.add(
+ js('$className.prototype.$setterName = #',
+ js.fun(args, js.return_(js('$receiver.$fieldName = v')))));
+ if (backend.isNeededForReflection(member)) {
+ task.precompiledFunction.add(
+ js('$className.prototype.$setterName.${namer.reflectableField} = 1'));
+ }
+ }
+
+ void generateReflectionDataForFieldGetterOrSetter(Element member,
+ String name,
+ ClassBuilder builder,
+ {bool isGetter}) {
+ Selector selector = isGetter
+ ? new Selector.getter(member.name, member.getLibrary())
+ : new Selector.setter(member.name, member.getLibrary());
+ String reflectionName = task.getReflectionName(selector, name);
+ if (reflectionName != null) {
+ var reflectable =
+ js(backend.isAccessibleByReflection(member) ? '1' : '0');
+ builder.addProperty('+$reflectionName', reflectable);
+ }
+ }
+}
diff --git a/sdk/lib/_internal/compiler/implementation/js_emitter/code_emitter_helper.dart b/sdk/lib/_internal/compiler/implementation/js_emitter/code_emitter_helper.dart
new file mode 100644
index 0000000..1adfce4
--- /dev/null
+++ b/sdk/lib/_internal/compiler/implementation/js_emitter/code_emitter_helper.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.
+
+part of dart2js.js_emitter;
+
+class CodeEmitterHelper {
+ CodeEmitterTask task;
+
+ Namer get namer => task.namer;
+
+ JavaScriptBackend get backend => task.backend;
+
+ Compiler get compiler => task.compiler;
+
+ String get n => task.n;
+
+ String get _ => task._;
+
+ String get N => task.N;
+}
diff --git a/sdk/lib/_internal/compiler/implementation/js_emitter/code_emitter_task.dart b/sdk/lib/_internal/compiler/implementation/js_emitter/code_emitter_task.dart
index dae8663..cea45c9 100644
--- a/sdk/lib/_internal/compiler/implementation/js_emitter/code_emitter_task.dart
+++ b/sdk/lib/_internal/compiler/implementation/js_emitter/code_emitter_task.dart
@@ -12,6 +12,10 @@
*/
class CodeEmitterTask extends CompilerTask {
final ContainerBuilder containerBuilder = new ContainerBuilder();
+ final ClassEmitter classEmitter = new ClassEmitter();
+ final NsmEmitter nsmEmitter = new NsmEmitter();
+ final TypeTestEmitter typeTestEmitter = new TypeTestEmitter();
+
bool needsDefineClass = false;
bool needsMixinSupport = false;
bool needsLazyInitializer = false;
@@ -26,11 +30,9 @@
String isolateProperties;
String classesCollector;
final Set<ClassElement> neededClasses = new Set<ClassElement>();
- final Set<ClassElement> rtiNeededClasses = new Set<ClassElement>();
final List<ClassElement> regularClasses = <ClassElement>[];
final List<ClassElement> deferredClasses = <ClassElement>[];
final List<ClassElement> nativeClasses = <ClassElement>[];
- final List<Selector> trivialNsmHandlers = <Selector>[];
final Map<String, String> mangledFieldNames = <String, String>{};
final Map<String, String> mangledGlobalFieldNames = <String, String>{};
final Set<String> recordedMangledNames = new Set<String>();
@@ -54,26 +56,6 @@
String get N => compiler.enableMinification ? "\n" : ";\n";
/**
- * Raw ClassElement symbols occuring in is-checks and type assertions. If the
- * program contains parameterized checks `x is Set<int>` and
- * `x is Set<String>` then the ClassElement `Set` will occur once in
- * [checkedClasses].
- */
- Set<ClassElement> checkedClasses;
-
- /**
- * The set of function types that checked, both explicity through tests of
- * typedefs and implicitly through type annotations in checked mode.
- */
- Set<FunctionType> checkedFunctionTypes;
-
- Map<ClassElement, Set<FunctionType>> checkedGenericFunctionTypes =
- new Map<ClassElement, Set<FunctionType>>();
-
- Set<FunctionType> checkedNonGenericFunctionTypes =
- new Set<FunctionType>();
-
- /**
* List of expressions and statements that will be included in the
* precompiled function.
*
@@ -99,30 +81,8 @@
final Map<Element, List<CodeBuffer>> elementBuffers =
new Map<Element, List<CodeBuffer>>();
- void registerDynamicFunctionTypeCheck(FunctionType functionType) {
- ClassElement classElement = Types.getClassContext(functionType);
- if (classElement != null) {
- checkedGenericFunctionTypes.putIfAbsent(classElement,
- () => new Set<FunctionType>()).add(functionType);
- } else {
- checkedNonGenericFunctionTypes.add(functionType);
- }
- }
-
final bool generateSourceMap;
- Iterable<ClassElement> cachedClassesUsingTypeVariableTests;
-
- Iterable<ClassElement> get classesUsingTypeVariableTests {
- if (cachedClassesUsingTypeVariableTests == null) {
- cachedClassesUsingTypeVariableTests = compiler.codegenWorld.isChecks
- .where((DartType t) => t is TypeVariableType)
- .map((TypeVariableType v) => v.element.getEnclosingClass())
- .toList();
- }
- return cachedClassesUsingTypeVariableTests;
- }
-
CodeEmitterTask(Compiler compiler, Namer namer, this.generateSourceMap)
: mainBuffer = new CodeBuffer(),
this.namer = namer,
@@ -130,38 +90,15 @@
super(compiler) {
nativeEmitter = new NativeEmitter(this);
containerBuilder.task = this;
+ classEmitter.task = this;
+ nsmEmitter.task = this;
+ typeTestEmitter.task = this;
}
void addComment(String comment, CodeBuffer buffer) {
buffer.write(jsAst.prettyPrint(js.comment(comment), compiler));
}
- void computeRequiredTypeChecks() {
- assert(checkedClasses == null && checkedFunctionTypes == null);
-
- backend.rti.addImplicitChecks(compiler.codegenWorld,
- classesUsingTypeVariableTests);
-
- checkedClasses = new Set<ClassElement>();
- checkedFunctionTypes = new Set<FunctionType>();
- compiler.codegenWorld.isChecks.forEach((DartType t) {
- if (t is InterfaceType) {
- checkedClasses.add(t.element);
- } else if (t is FunctionType) {
- checkedFunctionTypes.add(t);
- }
- });
- }
-
- ClassElement computeMixinClass(MixinApplicationElement mixinApplication) {
- ClassElement mixin = mixinApplication.mixin;
- while (mixin.isMixinApplication) {
- mixinApplication = mixin;
- mixin = mixinApplication.mixin;
- }
- return mixin;
- }
-
jsAst.Expression constantReference(Constant value) {
return constantEmitter.reference(value);
}
@@ -187,30 +124,6 @@
String get lazyInitializerName
=> '${namer.isolateName}.\$lazy';
- // Compact field specifications. The format of the field specification is
- // <accessorName>:<fieldName><suffix> where the suffix and accessor name
- // prefix are optional. The suffix directs the generation of getter and
- // setter methods. Each of the getter and setter has two bits to determine
- // the calling convention. Setter listed below, getter is similar.
- //
- // 00: no setter
- // 01: function(value) { this.field = value; }
- // 10: function(receiver, value) { receiver.field = value; }
- // 11: function(receiver, value) { this.field = value; }
- //
- // The suffix encodes 4 bits using three ASCII ranges of non-identifier
- // characters.
- static const FIELD_CODE_CHARACTERS = r"<=>?@{|}~%&'()*";
- static const NO_FIELD_CODE = 0;
- static const FIRST_FIELD_CODE = 1;
- static const RANGE1_FIRST = 0x3c; // <=>?@ encodes 1..5
- static const RANGE1_LAST = 0x40;
- static const RANGE2_FIRST = 0x7b; // {|}~ encodes 6..9
- static const RANGE2_LAST = 0x7e;
- static const RANGE3_FIRST = 0x25; // %&'()*+ encodes 10..16
- static const RANGE3_LAST = 0x2b;
- static const REFLECTION_MARKER = 0x2d;
-
jsAst.FunctionDeclaration get generateAccessorFunction {
const RANGE1_SIZE = RANGE1_LAST - RANGE1_FIRST + 1;
const RANGE2_SIZE = RANGE2_LAST - RANGE2_FIRST + 1;
@@ -366,238 +279,6 @@
]))])())];
}
- static const MAX_MINIFIED_LENGTH_FOR_DIFF_ENCODING = 4;
-
- // If we need fewer than this many noSuchMethod handlers we can save space by
- // just emitting them in JS, rather than emitting the JS needed to generate
- // them at run time.
- static const VERY_FEW_NO_SUCH_METHOD_HANDLERS = 10;
-
- /**
- * Adds (at runtime) the handlers to the Object class which catch calls to
- * methods that the object does not have. The handlers create an invocation
- * mirror object.
- *
- * The current version only gives you the minified name when minifying (when
- * not minifying this method is not called).
- *
- * In order to generate the noSuchMethod handlers we only need the minified
- * name of the method. We test the first character of the minified name to
- * determine if it is a getter or a setter, and we use the arguments array at
- * runtime to get the number of arguments and their values. If the method
- * involves named arguments etc. then we don't handle it here, but emit the
- * handler method directly on the Object class.
- *
- * The minified names are mostly 1-4 character names, which we emit in sorted
- * order (primary key is length, secondary ordering is lexicographic). This
- * gives an order like ... dD dI dX da ...
- *
- * Gzip is good with repeated text, but it can't diff-encode, so we do that
- * for it. We encode the minified names in a comma-separated string, but all
- * the 1-4 character names are encoded before the first comma as a series of
- * base 26 numbers. The last digit of each number is lower case, the others
- * are upper case, so 1 is "b" and 26 is "Ba".
- *
- * We think of the minified names as base 88 numbers using the ASCII
- * characters from # to z. The base 26 numbers each encode the delta from
- * the previous minified name to the next. So if there is a minified name
- * called Df and the next is Dh, then they are 2971 and 2973 when thought of
- * as base 88 numbers. The difference is 2, which is "c" in lower-case-
- * terminated base 26.
- *
- * The reason we don't encode long minified names with this method is that
- * decoding the base 88 numbers would overflow JavaScript's puny integers.
- *
- * There are some selectors that have a special calling convention (because
- * they are called with the receiver as the first argument). They need a
- * slightly different noSuchMethod handler, so we handle these first.
- */
- void addTrivialNsmHandlers(List<jsAst.Node> statements) {
- if (trivialNsmHandlers.length == 0) return;
- // Sort by calling convention, JS name length and by JS name.
- trivialNsmHandlers.sort((a, b) {
- bool aIsIntercepted = backend.isInterceptedName(a.name);
- bool bIsIntercepted = backend.isInterceptedName(b.name);
- if (aIsIntercepted != bIsIntercepted) return aIsIntercepted ? -1 : 1;
- String aName = namer.invocationMirrorInternalName(a);
- String bName = namer.invocationMirrorInternalName(b);
- if (aName.length != bName.length) return aName.length - bName.length;
- return aName.compareTo(bName);
- });
-
- // Find out how many selectors there are with the special calling
- // convention.
- int firstNormalSelector = trivialNsmHandlers.length;
- for (int i = 0; i < trivialNsmHandlers.length; i++) {
- if (!backend.isInterceptedName(trivialNsmHandlers[i].name)) {
- firstNormalSelector = i;
- break;
- }
- }
-
- // Get the short names (JS names, perhaps minified).
- Iterable<String> shorts = trivialNsmHandlers.map((selector) =>
- namer.invocationMirrorInternalName(selector));
- final diffShorts = <String>[];
- var diffEncoding = new StringBuffer();
-
- // Treat string as a number in base 88 with digits in ASCII order from # to
- // z. The short name sorting is based on length, and uses ASCII order for
- // equal length strings so this means that names are ascending. The hash
- // character, #, is never given as input, but we need it because it's the
- // implicit leading zero (otherwise we could not code names with leading
- // dollar signs).
- int fromBase88(String x) {
- int answer = 0;
- for (int i = 0; i < x.length; i++) {
- int c = x.codeUnitAt(i);
- // No support for Unicode minified identifiers in JS.
- assert(c >= $$ && c <= $z);
- answer *= 88;
- answer += c - $HASH;
- }
- return answer;
- }
-
- // Big endian encoding, A = 0, B = 1...
- // A lower case letter terminates the number.
- String toBase26(int x) {
- int c = x;
- var encodingChars = <int>[];
- encodingChars.add($a + (c % 26));
- while (true) {
- c ~/= 26;
- if (c == 0) break;
- encodingChars.add($A + (c % 26));
- }
- return new String.fromCharCodes(encodingChars.reversed.toList());
- }
-
- bool minify = compiler.enableMinification;
- bool useDiffEncoding = minify && shorts.length > 30;
-
- int previous = 0;
- int nameCounter = 0;
- for (String short in shorts) {
- // Emit period that resets the diff base to zero when we switch to normal
- // calling convention (this avoids the need to code negative diffs).
- if (useDiffEncoding && nameCounter == firstNormalSelector) {
- diffEncoding.write(".");
- previous = 0;
- }
- if (short.length <= MAX_MINIFIED_LENGTH_FOR_DIFF_ENCODING &&
- useDiffEncoding) {
- int base63 = fromBase88(short);
- int diff = base63 - previous;
- previous = base63;
- String base26Diff = toBase26(diff);
- diffEncoding.write(base26Diff);
- } else {
- if (useDiffEncoding || diffEncoding.length != 0) {
- diffEncoding.write(",");
- }
- diffEncoding.write(short);
- }
- nameCounter++;
- }
-
- // Startup code that loops over the method names and puts handlers on the
- // Object class to catch noSuchMethod invocations.
- ClassElement objectClass = compiler.objectClass;
- String createInvocationMirror = namer.isolateAccess(
- backend.getCreateInvocationMirror());
- String noSuchMethodName = namer.publicInstanceMethodNameByArity(
- Compiler.NO_SUCH_METHOD, Compiler.NO_SUCH_METHOD_ARG_COUNT);
- var type = 0;
- if (useDiffEncoding) {
- statements.addAll([
- js('var objectClassObject = '
- ' collectedClasses["${namer.getNameOfClass(objectClass)}"],'
- ' shortNames = "$diffEncoding".split(","),'
- ' nameNumber = 0,'
- ' diffEncodedString = shortNames[0],'
- ' calculatedShortNames = [0, 1]'), // 0, 1 are args for splice.
- js.if_('objectClassObject instanceof Array',
- js('objectClassObject = objectClassObject[1]')),
- js.for_('var i = 0', 'i < diffEncodedString.length', 'i++', [
- js('var codes = [],'
- ' diff = 0,'
- ' digit = diffEncodedString.charCodeAt(i)'),
- js.if_('digit == ${$PERIOD}', [
- js('nameNumber = 0'),
- js('digit = diffEncodedString.charCodeAt(++i)')
- ]),
- js.while_('digit <= ${$Z}', [
- js('diff *= 26'),
- js('diff += (digit - ${$A})'),
- js('digit = diffEncodedString.charCodeAt(++i)')
- ]),
- js('diff *= 26'),
- js('diff += (digit - ${$a})'),
- js('nameNumber += diff'),
- js.for_('var remaining = nameNumber',
- 'remaining > 0',
- 'remaining = (remaining / 88) | 0', [
- js('codes.unshift(${$HASH} + remaining % 88)')
- ]),
- js('calculatedShortNames.push('
- ' String.fromCharCode.apply(String, codes))')
- ]),
- js('shortNames.splice.apply(shortNames, calculatedShortNames)')
- ]);
- } else {
- // No useDiffEncoding version.
- Iterable<String> longs = trivialNsmHandlers.map((selector) =>
- selector.invocationMirrorMemberName);
- String longNamesConstant = minify ? "" :
- ',longNames = "${longs.join(",")}".split(",")';
- statements.add(
- js('var objectClassObject = '
- ' collectedClasses["${namer.getNameOfClass(objectClass)}"],'
- ' shortNames = "$diffEncoding".split(",")'
- ' $longNamesConstant'));
- statements.add(
- js.if_('objectClassObject instanceof Array',
- js('objectClassObject = objectClassObject[1]')));
- }
-
- String sliceOffset = ', (j < $firstNormalSelector) ? 1 : 0';
- if (firstNormalSelector == 0) sliceOffset = '';
- if (firstNormalSelector == shorts.length) sliceOffset = ', 1';
-
- String whatToPatch = nativeEmitter.handleNoSuchMethod ?
- "Object.prototype" :
- "objectClassObject";
-
- var params = ['name', 'short', 'type'];
- var sliceOffsetParam = '';
- var slice = 'Array.prototype.slice.call';
- if (!sliceOffset.isEmpty) {
- sliceOffsetParam = ', sliceOffset';
- params.add('sliceOffset');
- }
- statements.addAll([
- js.for_('var j = 0', 'j < shortNames.length', 'j++', [
- js('var type = 0'),
- js('var short = shortNames[j]'),
- js.if_('short[0] == "${namer.getterPrefix[0]}"', js('type = 1')),
- js.if_('short[0] == "${namer.setterPrefix[0]}"', js('type = 2')),
- // Generate call to:
- // createInvocationMirror(String name, internalName, type, arguments,
- // argumentNames)
- js('$whatToPatch[short] = #(${minify ? "shortNames" : "longNames"}[j], '
- 'short, type$sliceOffset)',
- js.fun(params, [js.return_(js.fun([],
- [js.return_(js(
- 'this.$noSuchMethodName('
- 'this, '
- '$createInvocationMirror('
- 'name, short, type, '
- '$slice(arguments$sliceOffsetParam), []))'))]))]))
- ])
- ]);
- }
-
jsAst.Fun get finishClassesFunction {
// Class descriptions are collected in a JS object.
// 'finishClasses' takes all collected descriptions and sets up
@@ -711,7 +392,7 @@
buildFinishClass(),
];
- addTrivialNsmHandlers(statements);
+ nsmEmitter.addTrivialNsmHandlers(statements);
statements.add(
js.forIn('cls', 'pendingClasses', js('finishClass(cls)'))
@@ -889,28 +570,6 @@
buffer.write("$isolate = $finishIsolateConstructorName($isolate)$N");
}
- bool fieldNeedsGetter(VariableElement field) {
- assert(field.isField());
- if (fieldAccessNeverThrows(field)) return false;
- return backend.shouldRetainGetter(field)
- || compiler.codegenWorld.hasInvokedGetter(field, compiler);
- }
-
- bool fieldNeedsSetter(VariableElement field) {
- assert(field.isField());
- if (fieldAccessNeverThrows(field)) return false;
- return (!field.modifiers.isFinalOrConst())
- && (backend.shouldRetainSetter(field)
- || compiler.codegenWorld.hasInvokedSetter(field, compiler));
- }
-
- // We never access a field in a closure (a captured variable) without knowing
- // that it is there. Therefore we don't need to use a getter (that will throw
- // if the getter method is missing), but can always access the field directly.
- static bool fieldAccessNeverThrows(VariableElement field) {
- return field is ClosureFieldElement;
- }
-
/// Returns the "reflection name" of an [Element] or [Selector].
/// The reflection name of a getter 'foo' is 'foo'.
/// The reflection name of a setter 'foo' is 'foo='.
@@ -1021,391 +680,6 @@
return ':$names';
}
- /**
- * Documentation wanted -- johnniwinther
- *
- * Invariant: [classElement] must be a declaration element.
- */
- void emitInstanceMembers(ClassElement classElement,
- ClassBuilder builder) {
- assert(invariant(classElement, classElement.isDeclaration));
-
- void visitMember(ClassElement enclosing, Element member) {
- assert(invariant(classElement, member.isDeclaration));
- if (member.isInstanceMember()) {
- containerBuilder.addMember(member, builder);
- }
- }
-
- classElement.implementation.forEachMember(
- visitMember,
- includeBackendMembers: true);
-
- if (identical(classElement, compiler.objectClass)
- && compiler.enabledNoSuchMethod) {
- // Emit the noSuchMethod handlers on the Object prototype now,
- // so that the code in the dynamicFunction helper can find
- // them. Note that this helper is invoked before analyzing the
- // full JS script.
- if (!nativeEmitter.handleNoSuchMethod) {
- emitNoSuchMethodHandlers(builder.addProperty);
- }
- }
- }
-
- void emitIsTests(ClassElement classElement, ClassBuilder builder) {
- assert(invariant(classElement, classElement.isDeclaration));
-
- void generateIsTest(Element other) {
- if (other == compiler.objectClass && other != classElement) {
- // Avoid emitting [:$isObject:] on all classes but [Object].
- return;
- }
- other = backend.getImplementationClass(other);
- builder.addProperty(namer.operatorIs(other), js('true'));
- }
-
- void generateIsFunctionTypeTest(FunctionType type) {
- String operator = namer.operatorIsType(type);
- builder.addProperty(operator, new jsAst.LiteralBool(true));
- }
-
- void generateFunctionTypeSignature(Element method, FunctionType type) {
- assert(method.isImplementation);
- jsAst.Expression thisAccess = new jsAst.This();
- Node node = method.parseNode(compiler);
- ClosureClassMap closureData =
- compiler.closureToClassMapper.closureMappingCache[node];
- if (closureData != null) {
- Element thisElement =
- closureData.freeVariableMapping[closureData.thisElement];
- if (thisElement != null) {
- assert(thisElement.hasFixedBackendName());
- String thisName = thisElement.fixedBackendName();
- thisAccess = js('this')[js.string(thisName)];
- }
- }
- RuntimeTypes rti = backend.rti;
- jsAst.Expression encoding = rti.getSignatureEncoding(type, thisAccess);
- String operatorSignature = namer.operatorSignature();
- builder.addProperty(operatorSignature, encoding);
- }
-
- void generateSubstitution(ClassElement cls, {bool emitNull: false}) {
- if (cls.typeVariables.isEmpty) return;
- RuntimeTypes rti = backend.rti;
- jsAst.Expression expression;
- bool needsNativeCheck = nativeEmitter.requiresNativeIsCheck(cls);
- expression = rti.getSupertypeSubstitution(
- classElement, cls, alwaysGenerateFunction: true);
- if (expression == null && (emitNull || needsNativeCheck)) {
- expression = new jsAst.LiteralNull();
- }
- if (expression != null) {
- builder.addProperty(namer.substitutionName(cls), expression);
- }
- }
-
- generateIsTestsOn(classElement, generateIsTest,
- generateIsFunctionTypeTest, generateFunctionTypeSignature,
- generateSubstitution);
- }
-
- void emitRuntimeTypeSupport(CodeBuffer buffer) {
- addComment('Runtime type support', buffer);
- RuntimeTypes rti = backend.rti;
- TypeChecks typeChecks = rti.requiredChecks;
-
- // Add checks to the constructors of instantiated classes.
- for (ClassElement cls in typeChecks) {
- // TODO(9556). The properties added to 'holder' should be generated
- // directly as properties of the class object, not added later.
- String holder = namer.isolateAccess(backend.getImplementationClass(cls));
- for (TypeCheck check in typeChecks[cls]) {
- ClassElement cls = check.cls;
- buffer.write('$holder.${namer.operatorIs(cls)}$_=${_}true$N');
- Substitution substitution = check.substitution;
- if (substitution != null) {
- CodeBuffer body =
- jsAst.prettyPrint(substitution.getCode(rti, false), compiler);
- buffer.write('$holder.${namer.substitutionName(cls)}$_=${_}');
- buffer.write(body);
- buffer.write('$N');
- }
- };
- }
-
- void addSignature(FunctionType type) {
- jsAst.Expression encoding = rti.getTypeEncoding(type);
- buffer.add('${namer.signatureName(type)}$_=${_}');
- buffer.write(jsAst.prettyPrint(encoding, compiler));
- buffer.add('$N');
- }
-
- checkedNonGenericFunctionTypes.forEach(addSignature);
-
- checkedGenericFunctionTypes.forEach((_, Set<FunctionType> functionTypes) {
- functionTypes.forEach(addSignature);
- });
- }
-
- /**
- * Returns the classes with constructors used as a 'holder' in
- * [emitRuntimeTypeSupport].
- * TODO(9556): Some cases will go away when the class objects are created as
- * complete. Not all classes will go away while constructors are referenced
- * from type substitutions.
- */
- Set<ClassElement> classesModifiedByEmitRuntimeTypeSupport() {
- TypeChecks typeChecks = backend.rti.requiredChecks;
- Set<ClassElement> result = new Set<ClassElement>();
- for (ClassElement cls in typeChecks) {
- for (TypeCheck check in typeChecks[cls]) {
- result.add(backend.getImplementationClass(cls));
- break;
- }
- }
- return result;
- }
-
- /**
- * Calls [addField] for each of the fields of [element].
- *
- * [element] must be a [ClassElement] or a [LibraryElement].
- *
- * If [element] is a [ClassElement], the static fields of the class are
- * visited if [visitStatics] is true and the instance fields are visited if
- * [visitStatics] is false.
- *
- * If [element] is a [LibraryElement], [visitStatics] must be true.
- *
- * When visiting the instance fields of a class, the fields of its superclass
- * are also visited if the class is instantiated.
- *
- * Invariant: [element] must be a declaration element.
- */
- void visitFields(Element element, bool visitStatics, AcceptField f) {
- assert(invariant(element, element.isDeclaration));
-
- bool isClass = false;
- bool isLibrary = false;
- if (element.isClass()) {
- isClass = true;
- } else if (element.isLibrary()) {
- isLibrary = true;
- assert(invariant(element, visitStatics));
- } else {
- throw new SpannableAssertionFailure(
- element, 'Expected a ClassElement or a LibraryElement.');
- }
-
- // If the class is never instantiated we still need to set it up for
- // inheritance purposes, but we can simplify its JavaScript constructor.
- bool isInstantiated =
- compiler.codegenWorld.instantiatedClasses.contains(element);
-
- void visitField(Element holder, VariableElement field) {
- assert(invariant(element, field.isDeclaration));
- SourceString name = field.name;
-
- // Keep track of whether or not we're dealing with a field mixin
- // into a native class.
- bool isMixinNativeField =
- isClass && element.isNative() && holder.isMixinApplication;
-
- // See if we can dynamically create getters and setters.
- // We can only generate getters and setters for [element] since
- // the fields of super classes could be overwritten with getters or
- // setters.
- bool needsGetter = false;
- bool needsSetter = false;
- // We need to name shadowed fields differently, so they don't clash with
- // the non-shadowed field.
- bool isShadowed = false;
- if (isLibrary || isMixinNativeField || holder == element) {
- needsGetter = fieldNeedsGetter(field);
- needsSetter = fieldNeedsSetter(field);
- } else {
- ClassElement cls = element;
- isShadowed = cls.isShadowedByField(field);
- }
-
- if ((isInstantiated && !holder.isNative())
- || needsGetter
- || needsSetter) {
- String accessorName = isShadowed
- ? namer.shadowedFieldName(field)
- : namer.getNameOfField(field);
- String fieldName = field.hasFixedBackendName()
- ? field.fixedBackendName()
- : (isMixinNativeField ? name.slowToString() : accessorName);
- bool needsCheckedSetter = false;
- if (compiler.enableTypeAssertions
- && needsSetter
- && canGenerateCheckedSetter(field)) {
- needsCheckedSetter = true;
- needsSetter = false;
- }
- // Getters and setters with suffixes will be generated dynamically.
- f(field, fieldName, accessorName, needsGetter, needsSetter,
- needsCheckedSetter);
- }
- }
-
- if (isLibrary) {
- LibraryElement library = element;
- library.implementation.forEachLocalMember((Element member) {
- if (member.isField()) visitField(library, member);
- });
- } else if (visitStatics) {
- ClassElement cls = element;
- cls.implementation.forEachStaticField(visitField);
- } else {
- ClassElement cls = element;
- // TODO(kasperl): We should make sure to only emit one version of
- // overridden fields. Right now, we rely on the ordering so the
- // fields pulled in from mixins are replaced with the fields from
- // the class definition.
-
- // If a class is not instantiated then we add the field just so we can
- // generate the field getter/setter dynamically. Since this is only
- // allowed on fields that are in [element] we don't need to visit
- // superclasses for non-instantiated classes.
- cls.implementation.forEachInstanceField(
- visitField, includeSuperAndInjectedMembers: isInstantiated);
- }
- }
-
- void generateReflectionDataForFieldGetterOrSetter(Element member,
- String name,
- ClassBuilder builder,
- {bool isGetter}) {
- Selector selector = isGetter
- ? new Selector.getter(member.name, member.getLibrary())
- : new Selector.setter(member.name, member.getLibrary());
- String reflectionName = getReflectionName(selector, name);
- if (reflectionName != null) {
- var reflectable =
- js(backend.isAccessibleByReflection(member) ? '1' : '0');
- builder.addProperty('+$reflectionName', reflectable);
- }
- }
-
- void generateGetter(Element member, String fieldName, String accessorName,
- ClassBuilder builder) {
- String getterName = namer.getterNameFromAccessorName(accessorName);
- ClassElement cls = member.getEnclosingClass();
- String className = namer.getNameOfClass(cls);
- String receiver = backend.isInterceptorClass(cls) ? 'receiver' : 'this';
- List<String> args = backend.isInterceptedMethod(member) ? ['receiver'] : [];
- precompiledFunction.add(
- js('$className.prototype.$getterName = #',
- js.fun(args, js.return_(js('$receiver.$fieldName')))));
- if (backend.isNeededForReflection(member)) {
- precompiledFunction.add(
- js('$className.prototype.$getterName.${namer.reflectableField} = 1'));
- }
- }
-
- void generateSetter(Element member, String fieldName, String accessorName,
- ClassBuilder builder) {
- String setterName = namer.setterNameFromAccessorName(accessorName);
- ClassElement cls = member.getEnclosingClass();
- String className = namer.getNameOfClass(cls);
- String receiver = backend.isInterceptorClass(cls) ? 'receiver' : 'this';
- List<String> args =
- backend.isInterceptedMethod(member) ? ['receiver', 'v'] : ['v'];
- precompiledFunction.add(
- js('$className.prototype.$setterName = #',
- js.fun(args, js.return_(js('$receiver.$fieldName = v')))));
- if (backend.isNeededForReflection(member)) {
- precompiledFunction.add(
- js('$className.prototype.$setterName.${namer.reflectableField} = 1'));
- }
- }
-
- bool canGenerateCheckedSetter(VariableElement field) {
- // We never generate accessors for top-level/static fields.
- if (!field.isInstanceMember()) return false;
- DartType type = field.computeType(compiler).unalias(compiler);
- if (type.element.isTypeVariable() ||
- (type is FunctionType && type.containsTypeVariables) ||
- type.treatAsDynamic ||
- type.element == compiler.objectClass) {
- // TODO(ngeoffray): Support type checks on type parameters.
- return false;
- }
- return true;
- }
-
- void generateCheckedSetter(Element member,
- String fieldName,
- String accessorName,
- ClassBuilder builder) {
- assert(canGenerateCheckedSetter(member));
- DartType type = member.computeType(compiler);
- // TODO(ahe): Generate a dynamic type error here.
- if (type.element.isErroneous()) return;
- type = type.unalias(compiler);
- // TODO(11273): Support complex subtype checks.
- type = type.asRaw();
- CheckedModeHelper helper =
- backend.getCheckedModeHelper(type, typeCast: false);
- FunctionElement helperElement = helper.getElement(compiler);
- String helperName = namer.isolateAccess(helperElement);
- List<jsAst.Expression> arguments = <jsAst.Expression>[js('v')];
- if (helperElement.computeSignature(compiler).parameterCount != 1) {
- arguments.add(js.string(namer.operatorIsType(type)));
- }
-
- String setterName = namer.setterNameFromAccessorName(accessorName);
- String receiver = backend.isInterceptorClass(member.getEnclosingClass())
- ? 'receiver' : 'this';
- List<String> args = backend.isInterceptedMethod(member)
- ? ['receiver', 'v']
- : ['v'];
- builder.addProperty(setterName,
- js.fun(args,
- js('$receiver.$fieldName = #', js(helperName)(arguments))));
- generateReflectionDataForFieldGetterOrSetter(
- member, setterName, builder, isGetter: false);
- }
-
- void emitClassConstructor(ClassElement classElement,
- ClassBuilder builder,
- String runtimeName) {
- List<String> fields = <String>[];
- if (!classElement.isNative()) {
- visitFields(classElement, false,
- (Element member,
- String name,
- String accessorName,
- bool needsGetter,
- bool needsSetter,
- bool needsCheckedSetter) {
- fields.add(name);
- });
- }
- String constructorName = namer.getNameOfClass(classElement);
- precompiledFunction.add(new jsAst.FunctionDeclaration(
- new jsAst.VariableDeclaration(constructorName),
- js.fun(fields, fields.map(
- (name) => js('this.$name = $name')).toList())));
- if (runtimeName == null) {
- runtimeName = constructorName;
- }
- precompiledFunction.addAll([
- js('$constructorName.builtin\$cls = "$runtimeName"'),
- js.if_('!"name" in $constructorName',
- js('$constructorName.name = "$constructorName"')),
- js('\$desc=\$collectedClasses.$constructorName'),
- js.if_('\$desc instanceof Array', js('\$desc = \$desc[1]')),
- js('$constructorName.prototype = \$desc'),
- ]);
-
- precompiledConstructorNames.add(js(constructorName));
- }
-
jsAst.FunctionDeclaration buildPrecompiledFunction() {
// TODO(ahe): Compute a hash code.
String name = 'dart_precompiled';
@@ -1419,313 +693,10 @@
js.fun([r'$collectedClasses'], precompiledFunction));
}
- void emitSuper(String superName, ClassBuilder builder) {
- /* Do nothing. */
- }
-
- void emitRuntimeName(String runtimeName, ClassBuilder builder) {
- /* Do nothing. */
- }
-
- void recordMangledField(Element member,
- String accessorName,
- String memberName) {
- if (!backend.shouldRetainGetter(member)) return;
- String previousName;
- if (member.isInstanceMember()) {
- previousName = mangledFieldNames.putIfAbsent(
- '${namer.getterPrefix}$accessorName',
- () => memberName);
- } else {
- previousName = mangledGlobalFieldNames.putIfAbsent(
- accessorName,
- () => memberName);
- }
- assert(invariant(member, previousName == memberName,
- message: '$previousName != ${memberName}'));
- }
-
- /// Returns `true` if fields added.
- bool emitFields(Element element,
- ClassBuilder builder,
- String superName,
- { bool classIsNative: false,
- bool emitStatics: false,
- bool onlyForRti: false }) {
- assert(!emitStatics || !onlyForRti);
- bool isClass = false;
- bool isLibrary = false;
- if (element.isClass()) {
- isClass = true;
- } else if (element.isLibrary()) {
- isLibrary = false;
- assert(invariant(element, emitStatics));
- } else {
- throw new SpannableAssertionFailure(
- element, 'Must be a ClassElement or a LibraryElement');
- }
- StringBuffer buffer = new StringBuffer();
- if (emitStatics) {
- assert(invariant(element, superName == null, message: superName));
- } else {
- assert(invariant(element, superName != null));
- String nativeName =
- namer.getPrimitiveInterceptorRuntimeName(element);
- if (nativeName != null) {
- buffer.write('$nativeName/');
- }
- buffer.write('$superName;');
- }
- int bufferClassLength = buffer.length;
-
- String separator = '';
-
- var fieldMetadata = [];
- bool hasMetadata = false;
-
- if (!onlyForRti) {
- visitFields(element, emitStatics,
- (VariableElement field,
- String name,
- String accessorName,
- bool needsGetter,
- bool needsSetter,
- bool needsCheckedSetter) {
- // Ignore needsCheckedSetter - that is handled below.
- bool needsAccessor = (needsGetter || needsSetter);
- // We need to output the fields for non-native classes so we can auto-
- // generate the constructor. For native classes there are no
- // constructors, so we don't need the fields unless we are generating
- // accessors at runtime.
- if (!classIsNative || needsAccessor) {
- buffer.write(separator);
- separator = ',';
- var metadata = buildMetadataFunction(field);
- if (metadata != null) {
- hasMetadata = true;
- } else {
- metadata = new jsAst.LiteralNull();
- }
- fieldMetadata.add(metadata);
- recordMangledField(field, accessorName, field.name.slowToString());
- if (!needsAccessor) {
- // Emit field for constructor generation.
- assert(!classIsNative);
- buffer.write(name);
- } else {
- // Emit (possibly renaming) field name so we can add accessors at
- // runtime.
- buffer.write(accessorName);
- if (name != accessorName) {
- buffer.write(':$name');
- // Only the native classes can have renaming accessors.
- assert(classIsNative);
- }
-
- int getterCode = 0;
- if (needsGetter) {
- if (field.isInstanceMember()) {
- // 01: function() { return this.field; }
- // 10: function(receiver) { return receiver.field; }
- // 11: function(receiver) { return this.field; }
- bool isIntercepted = backend.fieldHasInterceptedGetter(field);
- getterCode += isIntercepted ? 2 : 0;
- getterCode += backend.isInterceptorClass(element) ? 0 : 1;
- // TODO(sra): 'isInterceptorClass' might not be the correct test
- // for methods forced to use the interceptor convention because
- // the method's class was elsewhere mixed-in to an interceptor.
- assert(!field.isInstanceMember() || getterCode != 0);
- if (isIntercepted) {
- interceptorInvocationNames.add(namer.getterName(field));
- }
- } else {
- getterCode = 1;
- }
- }
- int setterCode = 0;
- if (needsSetter) {
- if (field.isInstanceMember()) {
- // 01: function(value) { this.field = value; }
- // 10: function(receiver, value) { receiver.field = value; }
- // 11: function(receiver, value) { this.field = value; }
- bool isIntercepted = backend.fieldHasInterceptedSetter(field);
- setterCode += isIntercepted ? 2 : 0;
- setterCode += backend.isInterceptorClass(element) ? 0 : 1;
- assert(!field.isInstanceMember() || setterCode != 0);
- if (isIntercepted) {
- interceptorInvocationNames.add(namer.setterName(field));
- }
- } else {
- setterCode = 1;
- }
- }
- int code = getterCode + (setterCode << 2);
- if (code == 0) {
- compiler.reportInternalError(
- field, 'Internal error: code is 0 ($element/$field)');
- } else {
- buffer.write(FIELD_CODE_CHARACTERS[code - FIRST_FIELD_CODE]);
- }
- }
- if (backend.isAccessibleByReflection(field)) {
- buffer.write(new String.fromCharCode(REFLECTION_MARKER));
- }
- }
- });
- }
-
- bool fieldsAdded = buffer.length > bufferClassLength;
- String compactClassData = buffer.toString();
- jsAst.Expression classDataNode = js.string(compactClassData);
- if (hasMetadata) {
- fieldMetadata.insert(0, classDataNode);
- classDataNode = new jsAst.ArrayInitializer.from(fieldMetadata);
- }
- builder.addProperty('', classDataNode);
- return fieldsAdded;
- }
-
- void emitClassGettersSetters(ClassElement classElement,
- ClassBuilder builder) {
-
- visitFields(classElement, false,
- (VariableElement member,
- String name,
- String accessorName,
- bool needsGetter,
- bool needsSetter,
- bool needsCheckedSetter) {
- compiler.withCurrentElement(member, () {
- if (needsCheckedSetter) {
- assert(!needsSetter);
- generateCheckedSetter(member, name, accessorName, builder);
- }
- if (needsGetter) {
- generateGetter(member, name, accessorName, builder);
- }
- if (needsSetter) {
- generateSetter(member, name, accessorName, builder);
- }
- });
- });
- }
-
- /**
- * Documentation wanted -- johnniwinther
- *
- * Invariant: [classElement] must be a declaration element.
- */
void generateClass(ClassElement classElement, CodeBuffer buffer) {
- final onlyForRti = rtiNeededClasses.contains(classElement);
-
- assert(invariant(classElement, classElement.isDeclaration));
- assert(invariant(classElement, !classElement.isNative() || onlyForRti));
-
- needsDefineClass = true;
- String className = namer.getNameOfClass(classElement);
-
- ClassElement superclass = classElement.superclass;
- String superName = "";
- if (superclass != null) {
- superName = namer.getNameOfClass(superclass);
- }
- String runtimeName =
- namer.getPrimitiveInterceptorRuntimeName(classElement);
-
- if (classElement.isMixinApplication) {
- String mixinName = namer.getNameOfClass(computeMixinClass(classElement));
- superName = '$superName+$mixinName';
- needsMixinSupport = true;
- }
-
- ClassBuilder builder = new ClassBuilder();
- emitClassConstructor(classElement, builder, runtimeName);
- emitSuper(superName, builder);
- emitRuntimeName(runtimeName, builder);
- emitFields(classElement, builder, superName, onlyForRti: onlyForRti);
- emitClassGettersSetters(classElement, builder);
- if (!classElement.isMixinApplication) {
- emitInstanceMembers(classElement, builder);
- }
- emitIsTests(classElement, builder);
-
- emitClassBuilderWithReflectionData(
- className, classElement, builder, buffer);
+ classEmitter.generateClass(classElement, buffer);
}
- void emitClassBuilderWithReflectionData(String className,
- ClassElement classElement,
- ClassBuilder builder,
- CodeBuffer buffer) {
- var metadata = buildMetadataFunction(classElement);
- if (metadata != null) {
- builder.addProperty("@", metadata);
- }
-
- if (backend.isNeededForReflection(classElement)) {
- Link typeVars = classElement.typeVariables;
- List properties = [];
- for (TypeVariableType typeVar in typeVars) {
- properties.add(js.string(typeVar.name.slowToString()));
- properties.add(js.toExpression(reifyType(typeVar.element.bound)));
- }
-
- ClassElement superclass = classElement.superclass;
- bool hasSuper = superclass != null;
- if ((!properties.isEmpty && !hasSuper) ||
- (hasSuper && superclass.typeVariables != typeVars)) {
- builder.addProperty('<>', new jsAst.ArrayInitializer.from(properties));
- }
- }
- List<CodeBuffer> classBuffers = elementBuffers[classElement];
- if (classBuffers == null) {
- classBuffers = [];
- } else {
- elementBuffers.remove(classElement);
- }
- CodeBuffer statics = new CodeBuffer();
- statics.write('{$n');
- bool hasStatics = false;
- ClassBuilder staticsBuilder = new ClassBuilder();
- if (emitFields(classElement, staticsBuilder, null, emitStatics: true)) {
- hasStatics = true;
- statics.write('"":$_');
- statics.write(
- jsAst.prettyPrint(staticsBuilder.properties.single.value, compiler));
- statics.write(',$n');
- }
- for (CodeBuffer classBuffer in classBuffers) {
- // TODO(ahe): What about deferred?
- if (classBuffer != null) {
- hasStatics = true;
- statics.addBuffer(classBuffer);
- }
- }
- statics.write('}$n');
- if (hasStatics) {
- builder.addProperty('static', new jsAst.Blob(statics));
- }
-
- // TODO(ahe): This method (generateClass) should return a jsAst.Expression.
- if (!buffer.isEmpty) {
- buffer.write(',$n$n');
- }
- buffer.write('$className:$_');
- buffer.write(jsAst.prettyPrint(builder.toObjectInitializer(), compiler));
- String reflectionName = getReflectionName(classElement, className);
- if (reflectionName != null) {
- List<int> interfaces = <int>[];
- for (DartType interface in classElement.interfaces) {
- interfaces.add(reifyType(interface));
- }
- buffer.write(',$n$n"+$reflectionName": $interfaces');
- }
- }
-
- /// If this is true then we can generate the noSuchMethod handlers at startup
- /// time, instead of them being emitted as part of the Object class.
- bool get generateTrivialNsmHandlers => true;
-
int _selectorRank(Selector selector) {
int arity = selector.argumentCount * 3;
if (selector.isGetter()) return arity + 2;
@@ -1741,196 +712,6 @@
}
/**
- * Returns a mapping containing all checked function types for which [type]
- * can be a subtype. A function type is mapped to [:true:] if [type] is
- * statically known to be a subtype of it and to [:false:] if [type] might
- * be a subtype, provided with the right type arguments.
- */
- // TODO(johnniwinther): Change to return a mapping from function types to
- // a set of variable points and use this to detect statically/dynamically
- // known subtype relations.
- Map<FunctionType, bool> getFunctionTypeChecksOn(DartType type) {
- Map<FunctionType, bool> functionTypeMap =
- new LinkedHashMap<FunctionType, bool>();
- for (FunctionType functionType in checkedFunctionTypes) {
- if (compiler.types.isSubtype(type, functionType)) {
- functionTypeMap[functionType] = true;
- } else if (compiler.types.isPotentialSubtype(type, functionType)) {
- functionTypeMap[functionType] = false;
- }
- }
- // TODO(johnniwinther): Ensure stable ordering of the keys.
- return functionTypeMap;
- }
-
- /**
- * Generate "is tests" for [cls]: itself, and the "is tests" for the
- * classes it implements and type argument substitution functions for these
- * tests. We don't need to add the "is tests" of the super class because
- * they will be inherited at runtime, but we may need to generate the
- * substitutions, because they may have changed.
- */
- void generateIsTestsOn(ClassElement cls,
- void emitIsTest(Element element),
- FunctionTypeTestEmitter emitIsFunctionTypeTest,
- FunctionTypeSignatureEmitter emitFunctionTypeSignature,
- SubstitutionEmitter emitSubstitution) {
- if (checkedClasses.contains(cls)) {
- emitIsTest(cls);
- emitSubstitution(cls);
- }
-
- RuntimeTypes rti = backend.rti;
- ClassElement superclass = cls.superclass;
-
- bool haveSameTypeVariables(ClassElement a, ClassElement b) {
- if (a.isClosure()) return true;
- if (b.isUnnamedMixinApplication) {
- return false;
- }
- return a.typeVariables == b.typeVariables;
- }
-
- if (superclass != null && superclass != compiler.objectClass &&
- !haveSameTypeVariables(cls, superclass)) {
- // We cannot inherit the generated substitutions, because the type
- // variable layout for this class is different. Instead we generate
- // substitutions for all checks and make emitSubstitution a NOP for the
- // rest of this function.
- Set<ClassElement> emitted = new Set<ClassElement>();
- // TODO(karlklose): move the computation of these checks to
- // RuntimeTypeInformation.
- if (backend.classNeedsRti(cls)) {
- emitSubstitution(superclass, emitNull: true);
- emitted.add(superclass);
- }
- for (DartType supertype in cls.allSupertypes) {
- ClassElement superclass = supertype.element;
- if (classesUsingTypeVariableTests.contains(superclass)) {
- emitSubstitution(superclass, emitNull: true);
- emitted.add(superclass);
- }
- for (ClassElement check in checkedClasses) {
- if (supertype.element == check && !emitted.contains(check)) {
- // Generate substitution. If no substitution is necessary, emit
- // [:null:] to overwrite a (possibly) existing substitution from the
- // super classes.
- emitSubstitution(check, emitNull: true);
- emitted.add(check);
- }
- }
- }
- void emitNothing(_, {emitNull}) {};
- emitSubstitution = emitNothing;
- }
-
- Set<Element> generated = new Set<Element>();
- // A class that defines a [:call:] method implicitly implements
- // [Function] and needs checks for all typedefs that are used in is-checks.
- if (checkedClasses.contains(compiler.functionClass) ||
- !checkedFunctionTypes.isEmpty) {
- Element call = cls.lookupLocalMember(Compiler.CALL_OPERATOR_NAME);
- if (call == null) {
- // If [cls] is a closure, it has a synthetic call operator method.
- call = cls.lookupBackendMember(Compiler.CALL_OPERATOR_NAME);
- }
- if (call != null && call.isFunction()) {
- generateInterfacesIsTests(compiler.functionClass,
- emitIsTest,
- emitSubstitution,
- generated);
- FunctionType callType = call.computeType(compiler);
- Map<FunctionType, bool> functionTypeChecks =
- getFunctionTypeChecksOn(callType);
- generateFunctionTypeTests(call, callType, functionTypeChecks,
- emitFunctionTypeSignature, emitIsFunctionTypeTest);
- }
- }
-
- for (DartType interfaceType in cls.interfaces) {
- generateInterfacesIsTests(interfaceType.element, emitIsTest,
- emitSubstitution, generated);
- }
- }
-
- /**
- * Generate "is tests" where [cls] is being implemented.
- */
- void generateInterfacesIsTests(ClassElement cls,
- void emitIsTest(ClassElement element),
- SubstitutionEmitter emitSubstitution,
- Set<Element> alreadyGenerated) {
- void tryEmitTest(ClassElement check) {
- if (!alreadyGenerated.contains(check) && checkedClasses.contains(check)) {
- alreadyGenerated.add(check);
- emitIsTest(check);
- emitSubstitution(check);
- }
- };
-
- tryEmitTest(cls);
-
- for (DartType interfaceType in cls.interfaces) {
- Element element = interfaceType.element;
- tryEmitTest(element);
- generateInterfacesIsTests(element, emitIsTest, emitSubstitution,
- alreadyGenerated);
- }
-
- // We need to also emit "is checks" for the superclass and its supertypes.
- ClassElement superclass = cls.superclass;
- if (superclass != null) {
- tryEmitTest(superclass);
- generateInterfacesIsTests(superclass, emitIsTest, emitSubstitution,
- alreadyGenerated);
- }
- }
-
- static const int MAX_FUNCTION_TYPE_PREDICATES = 10;
-
- /**
- * Generates function type checks on [method] with type [methodType] against
- * the function type checks in [functionTypeChecks].
- */
- void generateFunctionTypeTests(
- Element method,
- FunctionType methodType,
- Map<FunctionType, bool> functionTypeChecks,
- FunctionTypeSignatureEmitter emitFunctionTypeSignature,
- FunctionTypeTestEmitter emitIsFunctionTypeTest) {
- bool hasDynamicFunctionTypeCheck = false;
- int neededPredicates = 0;
- functionTypeChecks.forEach((FunctionType functionType, bool knownSubtype) {
- if (!knownSubtype) {
- registerDynamicFunctionTypeCheck(functionType);
- hasDynamicFunctionTypeCheck = true;
- } else if (!backend.rti.isSimpleFunctionType(functionType)) {
- // Simple function types are always checked using predicates and should
- // not provoke generation of signatures.
- neededPredicates++;
- }
- });
- bool alwaysUseSignature = false;
- if (hasDynamicFunctionTypeCheck ||
- neededPredicates > MAX_FUNCTION_TYPE_PREDICATES) {
- emitFunctionTypeSignature(method, methodType);
- alwaysUseSignature = true;
- }
- functionTypeChecks.forEach((FunctionType functionType, bool knownSubtype) {
- if (knownSubtype) {
- if (backend.rti.isSimpleFunctionType(functionType)) {
- // Simple function types are always checked using predicates.
- emitIsFunctionTypeTest(functionType);
- } else if (alwaysUseSignature) {
- registerDynamicFunctionTypeCheck(functionType);
- } else {
- emitIsFunctionTypeTest(functionType);
- }
- }
- });
- }
-
- /**
* Return a function that returns true if its argument is a class
* that needs to be emitted.
*/
@@ -2137,126 +918,6 @@
''');
}
- // Identify the noSuchMethod handlers that are so simple that we can
- // generate them programatically.
- bool isTrivialNsmHandler(
- int type, List argNames, Selector selector, String internalName) {
- if (!generateTrivialNsmHandlers) return false;
- // Check for interceptor calling convention.
- if (backend.isInterceptedName(selector.name)) {
- // We can handle the calling convention used by intercepted names in the
- // diff encoding, but we don't use that for non-minified code.
- if (!compiler.enableMinification) return false;
- String shortName = namer.invocationMirrorInternalName(selector);
- if (shortName.length > MAX_MINIFIED_LENGTH_FOR_DIFF_ENCODING) {
- return false;
- }
- }
- // Check for named arguments.
- if (argNames.length != 0) return false;
- // Check for unexpected name (this doesn't really happen).
- if (internalName.startsWith(namer.getterPrefix[0])) return type == 1;
- if (internalName.startsWith(namer.setterPrefix[0])) return type == 2;
- return type == 0;
- }
-
- void emitNoSuchMethodHandlers(DefineStubFunction defineStub) {
- // Do not generate no such method handlers if there is no class.
- if (compiler.codegenWorld.instantiatedClasses.isEmpty) return;
-
- String noSuchMethodName = namer.publicInstanceMethodNameByArity(
- Compiler.NO_SUCH_METHOD, Compiler.NO_SUCH_METHOD_ARG_COUNT);
-
- // Keep track of the JavaScript names we've already added so we
- // do not introduce duplicates (bad for code size).
- Map<String, Selector> addedJsNames = new Map<String, Selector>();
-
- void addNoSuchMethodHandlers(SourceString ignore, Set<Selector> selectors) {
- // Cache the object class and type.
- ClassElement objectClass = compiler.objectClass;
- DartType objectType = objectClass.computeType(compiler);
-
- for (Selector selector in selectors) {
- TypeMask mask = selector.mask;
- if (mask == null) {
- mask = new TypeMask.subclass(compiler.objectClass);
- }
-
- if (!mask.needsNoSuchMethodHandling(selector, compiler)) continue;
- String jsName = namer.invocationMirrorInternalName(selector);
- addedJsNames[jsName] = selector;
- String reflectionName = getReflectionName(selector, jsName);
- if (reflectionName != null) {
- mangledFieldNames[jsName] = reflectionName;
- }
- }
- }
-
- compiler.codegenWorld.invokedNames.forEach(addNoSuchMethodHandlers);
- compiler.codegenWorld.invokedGetters.forEach(addNoSuchMethodHandlers);
- compiler.codegenWorld.invokedSetters.forEach(addNoSuchMethodHandlers);
-
- // Set flag used by generateMethod helper below. If we have very few
- // handlers we use defineStub for them all, rather than try to generate them
- // at runtime.
- bool haveVeryFewNoSuchMemberHandlers =
- (addedJsNames.length < VERY_FEW_NO_SUCH_METHOD_HANDLERS);
-
- jsAst.Expression generateMethod(String jsName, Selector selector) {
- // Values match JSInvocationMirror in js-helper library.
- int type = selector.invocationMirrorKind;
- List<jsAst.Parameter> parameters = <jsAst.Parameter>[];
- CodeBuffer args = new CodeBuffer();
- for (int i = 0; i < selector.argumentCount; i++) {
- parameters.add(new jsAst.Parameter('\$$i'));
- }
-
- List<jsAst.Expression> argNames =
- selector.getOrderedNamedArguments().map((SourceString name) =>
- js.string(name.slowToString())).toList();
-
- String methodName = selector.invocationMirrorMemberName;
- String internalName = namer.invocationMirrorInternalName(selector);
- String reflectionName = getReflectionName(selector, internalName);
- if (!haveVeryFewNoSuchMemberHandlers &&
- isTrivialNsmHandler(type, argNames, selector, internalName) &&
- reflectionName == null) {
- trivialNsmHandlers.add(selector);
- return null;
- }
-
- assert(backend.isInterceptedName(Compiler.NO_SUCH_METHOD));
- jsAst.Expression expression = js('this.$noSuchMethodName')(
- [js('this'),
- namer.elementAccess(backend.getCreateInvocationMirror())([
- js.string(compiler.enableMinification ?
- internalName : methodName),
- js.string(internalName),
- type,
- new jsAst.ArrayInitializer.from(
- parameters.map((param) => js(param.name)).toList()),
- new jsAst.ArrayInitializer.from(argNames)])]);
- parameters = backend.isInterceptedName(selector.name)
- ? ([new jsAst.Parameter('\$receiver')]..addAll(parameters))
- : parameters;
- return js.fun(parameters, js.return_(expression));
- }
-
- for (String jsName in addedJsNames.keys.toList()..sort()) {
- Selector selector = addedJsNames[jsName];
- jsAst.Expression method = generateMethod(jsName, selector);
- if (method != null) {
- defineStub(jsName, method);
- String reflectionName = getReflectionName(selector, jsName);
- if (reflectionName != null) {
- bool accessible = compiler.world.allFunctions.filter(selector).any(
- (Element e) => backend.isAccessibleByReflection(e));
- defineStub('+$reflectionName', js(accessible ? '1' : '0'));
- }
- }
- }
- }
-
String buildIsolateSetup(CodeBuffer buffer,
Element appMain,
Element isolateMain) {
@@ -2571,16 +1232,16 @@
// these are thought to not have been instantiated, so we neeed to be able
// to identify them later and make sure we only emit "empty shells" without
// fields, etc.
- computeRtiNeededClasses();
- rtiNeededClasses.removeAll(neededClasses);
+ typeTestEmitter.computeRtiNeededClasses();
+ typeTestEmitter.rtiNeededClasses.removeAll(neededClasses);
// rtiNeededClasses now contains only the "empty shells".
- neededClasses.addAll(rtiNeededClasses);
+ neededClasses.addAll(typeTestEmitter.rtiNeededClasses);
// 5. Finally, sort the classes.
List<ClassElement> sortedClasses = Elements.sortedByPosition(neededClasses);
for (ClassElement element in sortedClasses) {
- if (rtiNeededClasses.contains(element)) {
+ if (typeTestEmitter.rtiNeededClasses.contains(element)) {
regularClasses.add(element);
} else if (Elements.isNativeOrExtendsNative(element)) {
// For now, native classes and related classes cannot be deferred.
@@ -2597,55 +1258,6 @@
}
}
- Set<ClassElement> computeRtiNeededClasses() {
- void addClassWithSuperclasses(ClassElement cls) {
- rtiNeededClasses.add(cls);
- for (ClassElement superclass = cls.superclass;
- superclass != null;
- superclass = superclass.superclass) {
- rtiNeededClasses.add(superclass);
- }
- }
-
- void addClassesWithSuperclasses(Iterable<ClassElement> classes) {
- for (ClassElement cls in classes) {
- addClassWithSuperclasses(cls);
- }
- }
-
- // 1. Add classes that are referenced by type arguments or substitutions in
- // argument checks.
- // TODO(karlklose): merge this case with 2 when unifying argument and
- // object checks.
- RuntimeTypes rti = backend.rti;
- rti.getRequiredArgumentClasses(backend).forEach((ClassElement c) {
- // Types that we represent with JS native types (like int and String) do
- // not need a class definition as we use the interceptor classes instead.
- if (!rti.isJsNative(c)) {
- addClassWithSuperclasses(c);
- }
- });
-
- // 2. Add classes that are referenced by substitutions in object checks and
- // their superclasses.
- TypeChecks requiredChecks =
- rti.computeChecks(rtiNeededClasses, checkedClasses);
- Set<ClassElement> classesUsedInSubstitutions =
- rti.getClassesUsedInSubstitutions(backend, requiredChecks);
- addClassesWithSuperclasses(classesUsedInSubstitutions);
-
- // 3. Add classes that contain checked generic function types. These are
- // needed to store the signature encoding.
- for (FunctionType type in checkedFunctionTypes) {
- ClassElement contextClass = Types.getClassContext(type);
- if (contextClass != null) {
- rtiNeededClasses.add(contextClass);
- }
- }
-
- return rtiNeededClasses;
- }
-
// Returns a statement that takes care of performance critical
// common case for a one-shot interceptor, or null if there is no
// fast path.
@@ -2881,6 +1493,8 @@
void emitMapTypeToInterceptor(CodeBuffer buffer) {
// TODO(sra): Perhaps inject a constant instead?
// TODO(sra): Filter by subclasses of native types.
+ // TODO(13835): Don't generate this unless we generated the functions that
+ // use the data structure.
List<jsAst.Expression> elements = <jsAst.Expression>[];
ConstantHandler handler = compiler.constantHandler;
List<Constant> constants = handler.getConstantsForEmission();
@@ -2892,6 +1506,38 @@
ClassElement classElement = element;
elements.add(backend.emitter.constantReference(constant));
elements.add(js(namer.isolateAccess(classElement)));
+
+ // Create JavaScript Object map for by-name lookup of generative
+ // constructors. For example, the class A has three generative
+ // constructors
+ //
+ // class A {
+ // A() {}
+ // A.foo() {}
+ // A.bar() {}
+ // }
+ //
+ // Which are described by the map
+ //
+ // {"": A.A$, "foo": A.A$foo, "bar": A.A$bar}
+ //
+ // We expect most of the time the map will be a singleton.
+ var properties = [];
+ classElement.forEachMember(
+ (ClassElement enclosingClass, Element member) {
+ if (member.isGenerativeConstructor()) {
+ properties.add(
+ new jsAst.Property(
+ js.string(member.name.slowToString()),
+ new jsAst.VariableUse(
+ backend.namer.isolateAccess(member))));
+ }
+ },
+ includeBackendMembers: false,
+ includeSuperAndInjectedMembers: false);
+
+ var map = new jsAst.ObjectInitializer(properties);
+ elements.add(map);
}
}
}
@@ -3053,7 +1699,7 @@
measure(() {
// Compute the required type checks to know which classes need a
// 'is$' method.
- computeRequiredTypeChecks();
+ typeTestEmitter.computeRequiredTypeChecks();
computeNeededClasses();
@@ -3153,7 +1799,8 @@
if (element.isLibrary()) {
LibraryElement library = element;
ClassBuilder builder = new ClassBuilder();
- if (emitFields(library, builder, null, emitStatics: true)) {
+ if (classEmitter.emitFields(
+ library, builder, null, emitStatics: true)) {
List<CodeBuffer> buffers = elementBuffers[library];
var buffer = buffers[0];
if (buffer == null) {
@@ -3273,7 +1920,7 @@
containerBuilder.emitStaticFunctionGetters(mainBuffer);
- emitRuntimeTypeSupport(mainBuffer);
+ typeTestEmitter.emitRuntimeTypeSupport(mainBuffer);
emitGetInterceptorMethods(mainBuffer);
// Constants in checked mode call into RTI code to set type information
// which may need getInterceptor methods, so we have to make sure that
@@ -3503,3 +2150,6 @@
return compiler.deferredLoadTask.areAnyElementsDeferred;
}
}
+
+// TODO(ahe): Move code for interceptors to own file.
+// TODO(ahe): Move code for reifying metadata/types to own file.
diff --git a/sdk/lib/_internal/compiler/implementation/js_emitter/container_builder.dart b/sdk/lib/_internal/compiler/implementation/js_emitter/container_builder.dart
index 15ad85a..25a4fd3 100644
--- a/sdk/lib/_internal/compiler/implementation/js_emitter/container_builder.dart
+++ b/sdk/lib/_internal/compiler/implementation/js_emitter/container_builder.dart
@@ -8,23 +8,13 @@
/// JavaScript representations of libraries, class-sides, and instance-sides.
/// Initially, it is just a placeholder for code that is moved from
/// [CodeEmitterTask].
-class ContainerBuilder {
+class ContainerBuilder extends CodeEmitterHelper {
final Map<Element, Element> staticGetters = new Map<Element, Element>();
/// A cache of synthesized closures for top-level, static or
/// instance methods.
final Map<String, Element> methodClosures = <String, Element>{};
- CodeEmitterTask task;
-
- Namer get namer => task.namer;
-
- Compiler get compiler => task.compiler;
-
- String get N => task.N;
-
- JavaScriptBackend get backend => task.backend;
-
/**
* Generate stubs to handle invocation of methods with optional
* arguments.
@@ -339,8 +329,9 @@
FunctionType methodType = element.computeType(compiler);
Map<FunctionType, bool> functionTypeChecks =
- task.getFunctionTypeChecksOn(methodType);
- task.generateFunctionTypeTests(element, methodType, functionTypeChecks,
+ task.typeTestEmitter.getFunctionTypeChecksOn(methodType);
+ task.typeTestEmitter.generateFunctionTypeTests(
+ element, methodType, functionTypeChecks,
emitFunctionTypeSignature, emitIsFunctionTypeTest);
closureClassElement =
@@ -473,9 +464,10 @@
DartType memberType = member.computeType(compiler);
Map<FunctionType, bool> functionTypeChecks =
- task.getFunctionTypeChecksOn(memberType);
+ task.typeTestEmitter.getFunctionTypeChecksOn(memberType);
- task.generateFunctionTypeTests(member, memberType, functionTypeChecks,
+ task.typeTestEmitter.generateFunctionTypeTests(
+ member, memberType, functionTypeChecks,
emitFunctionTypeSignature, emitIsFunctionTypeTest);
closureClassElement =
diff --git a/sdk/lib/_internal/compiler/implementation/js_emitter/declarations.dart b/sdk/lib/_internal/compiler/implementation/js_emitter/declarations.dart
index 7a3e055..f21d3d8 100644
--- a/sdk/lib/_internal/compiler/implementation/js_emitter/declarations.dart
+++ b/sdk/lib/_internal/compiler/implementation/js_emitter/declarations.dart
@@ -59,3 +59,27 @@
// Instead, a closure that will invoke [main] is
// passed to [dartMainRunner].
""";
+
+// Compact field specifications. The format of the field specification is
+// <accessorName>:<fieldName><suffix> where the suffix and accessor name
+// prefix are optional. The suffix directs the generation of getter and
+// setter methods. Each of the getter and setter has two bits to determine
+// the calling convention. Setter listed below, getter is similar.
+//
+// 00: no setter
+// 01: function(value) { this.field = value; }
+// 10: function(receiver, value) { receiver.field = value; }
+// 11: function(receiver, value) { this.field = value; }
+//
+// The suffix encodes 4 bits using three ASCII ranges of non-identifier
+// characters.
+const FIELD_CODE_CHARACTERS = r"<=>?@{|}~%&'()*";
+const NO_FIELD_CODE = 0;
+const FIRST_FIELD_CODE = 1;
+const RANGE1_FIRST = 0x3c; // <=>?@ encodes 1..5
+const RANGE1_LAST = 0x40;
+const RANGE2_FIRST = 0x7b; // {|}~ encodes 6..9
+const RANGE2_LAST = 0x7e;
+const RANGE3_FIRST = 0x25; // %&'()*+ encodes 10..16
+const RANGE3_LAST = 0x2b;
+const REFLECTION_MARKER = 0x2d;
diff --git a/sdk/lib/_internal/compiler/implementation/js_emitter/helpers.dart b/sdk/lib/_internal/compiler/implementation/js_emitter/helpers.dart
new file mode 100644
index 0000000..017094b
--- /dev/null
+++ b/sdk/lib/_internal/compiler/implementation/js_emitter/helpers.dart
@@ -0,0 +1,14 @@
+// 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 dart2js.js_emitter;
+
+ClassElement computeMixinClass(MixinApplicationElement mixinApplication) {
+ ClassElement mixin = mixinApplication.mixin;
+ while (mixin.isMixinApplication) {
+ mixinApplication = mixin;
+ mixin = mixinApplication.mixin;
+ }
+ return mixin;
+}
diff --git a/sdk/lib/_internal/compiler/implementation/js_emitter/js_emitter.dart b/sdk/lib/_internal/compiler/implementation/js_emitter/js_emitter.dart
index dfd526b..8e9137c 100644
--- a/sdk/lib/_internal/compiler/implementation/js_emitter/js_emitter.dart
+++ b/sdk/lib/_internal/compiler/implementation/js_emitter/js_emitter.dart
@@ -56,8 +56,13 @@
relativize;
part 'class_builder.dart';
+part 'class_emitter.dart';
part 'closure_invocation_element.dart';
+part 'code_emitter_helper.dart';
part 'code_emitter_task.dart';
part 'container_builder.dart';
part 'declarations.dart';
+part 'helpers.dart';
+part 'nsm_emitter.dart';
part 'reflection_data_parser.dart';
+part 'type_test_emitter.dart';
diff --git a/sdk/lib/_internal/compiler/implementation/js_emitter/nsm_emitter.dart b/sdk/lib/_internal/compiler/implementation/js_emitter/nsm_emitter.dart
new file mode 100644
index 0000000..8b565f5
--- /dev/null
+++ b/sdk/lib/_internal/compiler/implementation/js_emitter/nsm_emitter.dart
@@ -0,0 +1,365 @@
+// 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 dart2js.js_emitter;
+
+class NsmEmitter extends CodeEmitterHelper {
+ final List<Selector> trivialNsmHandlers = <Selector>[];
+
+ /// If this is true then we can generate the noSuchMethod handlers at startup
+ /// time, instead of them being emitted as part of the Object class.
+ bool get generateTrivialNsmHandlers => true;
+
+ // If we need fewer than this many noSuchMethod handlers we can save space by
+ // just emitting them in JS, rather than emitting the JS needed to generate
+ // them at run time.
+ static const VERY_FEW_NO_SUCH_METHOD_HANDLERS = 10;
+
+ static const MAX_MINIFIED_LENGTH_FOR_DIFF_ENCODING = 4;
+
+ void emitNoSuchMethodHandlers(DefineStubFunction defineStub) {
+ // Do not generate no such method handlers if there is no class.
+ if (compiler.codegenWorld.instantiatedClasses.isEmpty) return;
+
+ String noSuchMethodName = namer.publicInstanceMethodNameByArity(
+ Compiler.NO_SUCH_METHOD, Compiler.NO_SUCH_METHOD_ARG_COUNT);
+
+ // Keep track of the JavaScript names we've already added so we
+ // do not introduce duplicates (bad for code size).
+ Map<String, Selector> addedJsNames = new Map<String, Selector>();
+
+ void addNoSuchMethodHandlers(SourceString ignore, Set<Selector> selectors) {
+ // Cache the object class and type.
+ ClassElement objectClass = compiler.objectClass;
+ DartType objectType = objectClass.computeType(compiler);
+
+ for (Selector selector in selectors) {
+ TypeMask mask = selector.mask;
+ if (mask == null) {
+ mask = new TypeMask.subclass(compiler.objectClass);
+ }
+
+ if (!mask.needsNoSuchMethodHandling(selector, compiler)) continue;
+ String jsName = namer.invocationMirrorInternalName(selector);
+ addedJsNames[jsName] = selector;
+ String reflectionName = task.getReflectionName(selector, jsName);
+ if (reflectionName != null) {
+ task.mangledFieldNames[jsName] = reflectionName;
+ }
+ }
+ }
+
+ compiler.codegenWorld.invokedNames.forEach(addNoSuchMethodHandlers);
+ compiler.codegenWorld.invokedGetters.forEach(addNoSuchMethodHandlers);
+ compiler.codegenWorld.invokedSetters.forEach(addNoSuchMethodHandlers);
+
+ // Set flag used by generateMethod helper below. If we have very few
+ // handlers we use defineStub for them all, rather than try to generate them
+ // at runtime.
+ bool haveVeryFewNoSuchMemberHandlers =
+ (addedJsNames.length < VERY_FEW_NO_SUCH_METHOD_HANDLERS);
+
+ jsAst.Expression generateMethod(String jsName, Selector selector) {
+ // Values match JSInvocationMirror in js-helper library.
+ int type = selector.invocationMirrorKind;
+ List<jsAst.Parameter> parameters = <jsAst.Parameter>[];
+ CodeBuffer args = new CodeBuffer();
+ for (int i = 0; i < selector.argumentCount; i++) {
+ parameters.add(new jsAst.Parameter('\$$i'));
+ }
+
+ List<jsAst.Expression> argNames =
+ selector.getOrderedNamedArguments().map((SourceString name) =>
+ js.string(name.slowToString())).toList();
+
+ String methodName = selector.invocationMirrorMemberName;
+ String internalName = namer.invocationMirrorInternalName(selector);
+ String reflectionName = task.getReflectionName(selector, internalName);
+ if (!haveVeryFewNoSuchMemberHandlers &&
+ isTrivialNsmHandler(type, argNames, selector, internalName) &&
+ reflectionName == null) {
+ trivialNsmHandlers.add(selector);
+ return null;
+ }
+
+ assert(backend.isInterceptedName(Compiler.NO_SUCH_METHOD));
+ jsAst.Expression expression = js('this.$noSuchMethodName')(
+ [js('this'),
+ namer.elementAccess(backend.getCreateInvocationMirror())([
+ js.string(compiler.enableMinification ?
+ internalName : methodName),
+ js.string(internalName),
+ type,
+ new jsAst.ArrayInitializer.from(
+ parameters.map((param) => js(param.name)).toList()),
+ new jsAst.ArrayInitializer.from(argNames)])]);
+ parameters = backend.isInterceptedName(selector.name)
+ ? ([new jsAst.Parameter('\$receiver')]..addAll(parameters))
+ : parameters;
+ return js.fun(parameters, js.return_(expression));
+ }
+
+ for (String jsName in addedJsNames.keys.toList()..sort()) {
+ Selector selector = addedJsNames[jsName];
+ jsAst.Expression method = generateMethod(jsName, selector);
+ if (method != null) {
+ defineStub(jsName, method);
+ String reflectionName = task.getReflectionName(selector, jsName);
+ if (reflectionName != null) {
+ bool accessible = compiler.world.allFunctions.filter(selector).any(
+ (Element e) => backend.isAccessibleByReflection(e));
+ defineStub('+$reflectionName', js(accessible ? '1' : '0'));
+ }
+ }
+ }
+ }
+
+ // Identify the noSuchMethod handlers that are so simple that we can
+ // generate them programatically.
+ bool isTrivialNsmHandler(
+ int type, List argNames, Selector selector, String internalName) {
+ if (!generateTrivialNsmHandlers) return false;
+ // Check for interceptor calling convention.
+ if (backend.isInterceptedName(selector.name)) {
+ // We can handle the calling convention used by intercepted names in the
+ // diff encoding, but we don't use that for non-minified code.
+ if (!compiler.enableMinification) return false;
+ String shortName = namer.invocationMirrorInternalName(selector);
+ if (shortName.length > MAX_MINIFIED_LENGTH_FOR_DIFF_ENCODING) {
+ return false;
+ }
+ }
+ // Check for named arguments.
+ if (argNames.length != 0) return false;
+ // Check for unexpected name (this doesn't really happen).
+ if (internalName.startsWith(namer.getterPrefix[0])) return type == 1;
+ if (internalName.startsWith(namer.setterPrefix[0])) return type == 2;
+ return type == 0;
+ }
+
+ /**
+ * Adds (at runtime) the handlers to the Object class which catch calls to
+ * methods that the object does not have. The handlers create an invocation
+ * mirror object.
+ *
+ * The current version only gives you the minified name when minifying (when
+ * not minifying this method is not called).
+ *
+ * In order to generate the noSuchMethod handlers we only need the minified
+ * name of the method. We test the first character of the minified name to
+ * determine if it is a getter or a setter, and we use the arguments array at
+ * runtime to get the number of arguments and their values. If the method
+ * involves named arguments etc. then we don't handle it here, but emit the
+ * handler method directly on the Object class.
+ *
+ * The minified names are mostly 1-4 character names, which we emit in sorted
+ * order (primary key is length, secondary ordering is lexicographic). This
+ * gives an order like ... dD dI dX da ...
+ *
+ * Gzip is good with repeated text, but it can't diff-encode, so we do that
+ * for it. We encode the minified names in a comma-separated string, but all
+ * the 1-4 character names are encoded before the first comma as a series of
+ * base 26 numbers. The last digit of each number is lower case, the others
+ * are upper case, so 1 is "b" and 26 is "Ba".
+ *
+ * We think of the minified names as base 88 numbers using the ASCII
+ * characters from # to z. The base 26 numbers each encode the delta from
+ * the previous minified name to the next. So if there is a minified name
+ * called Df and the next is Dh, then they are 2971 and 2973 when thought of
+ * as base 88 numbers. The difference is 2, which is "c" in lower-case-
+ * terminated base 26.
+ *
+ * The reason we don't encode long minified names with this method is that
+ * decoding the base 88 numbers would overflow JavaScript's puny integers.
+ *
+ * There are some selectors that have a special calling convention (because
+ * they are called with the receiver as the first argument). They need a
+ * slightly different noSuchMethod handler, so we handle these first.
+ */
+ void addTrivialNsmHandlers(List<jsAst.Node> statements) {
+ if (trivialNsmHandlers.length == 0) return;
+ // Sort by calling convention, JS name length and by JS name.
+ trivialNsmHandlers.sort((a, b) {
+ bool aIsIntercepted = backend.isInterceptedName(a.name);
+ bool bIsIntercepted = backend.isInterceptedName(b.name);
+ if (aIsIntercepted != bIsIntercepted) return aIsIntercepted ? -1 : 1;
+ String aName = namer.invocationMirrorInternalName(a);
+ String bName = namer.invocationMirrorInternalName(b);
+ if (aName.length != bName.length) return aName.length - bName.length;
+ return aName.compareTo(bName);
+ });
+
+ // Find out how many selectors there are with the special calling
+ // convention.
+ int firstNormalSelector = trivialNsmHandlers.length;
+ for (int i = 0; i < trivialNsmHandlers.length; i++) {
+ if (!backend.isInterceptedName(trivialNsmHandlers[i].name)) {
+ firstNormalSelector = i;
+ break;
+ }
+ }
+
+ // Get the short names (JS names, perhaps minified).
+ Iterable<String> shorts = trivialNsmHandlers.map((selector) =>
+ namer.invocationMirrorInternalName(selector));
+ final diffShorts = <String>[];
+ var diffEncoding = new StringBuffer();
+
+ // Treat string as a number in base 88 with digits in ASCII order from # to
+ // z. The short name sorting is based on length, and uses ASCII order for
+ // equal length strings so this means that names are ascending. The hash
+ // character, #, is never given as input, but we need it because it's the
+ // implicit leading zero (otherwise we could not code names with leading
+ // dollar signs).
+ int fromBase88(String x) {
+ int answer = 0;
+ for (int i = 0; i < x.length; i++) {
+ int c = x.codeUnitAt(i);
+ // No support for Unicode minified identifiers in JS.
+ assert(c >= $$ && c <= $z);
+ answer *= 88;
+ answer += c - $HASH;
+ }
+ return answer;
+ }
+
+ // Big endian encoding, A = 0, B = 1...
+ // A lower case letter terminates the number.
+ String toBase26(int x) {
+ int c = x;
+ var encodingChars = <int>[];
+ encodingChars.add($a + (c % 26));
+ while (true) {
+ c ~/= 26;
+ if (c == 0) break;
+ encodingChars.add($A + (c % 26));
+ }
+ return new String.fromCharCodes(encodingChars.reversed.toList());
+ }
+
+ bool minify = compiler.enableMinification;
+ bool useDiffEncoding = minify && shorts.length > 30;
+
+ int previous = 0;
+ int nameCounter = 0;
+ for (String short in shorts) {
+ // Emit period that resets the diff base to zero when we switch to normal
+ // calling convention (this avoids the need to code negative diffs).
+ if (useDiffEncoding && nameCounter == firstNormalSelector) {
+ diffEncoding.write(".");
+ previous = 0;
+ }
+ if (short.length <= MAX_MINIFIED_LENGTH_FOR_DIFF_ENCODING &&
+ useDiffEncoding) {
+ int base63 = fromBase88(short);
+ int diff = base63 - previous;
+ previous = base63;
+ String base26Diff = toBase26(diff);
+ diffEncoding.write(base26Diff);
+ } else {
+ if (useDiffEncoding || diffEncoding.length != 0) {
+ diffEncoding.write(",");
+ }
+ diffEncoding.write(short);
+ }
+ nameCounter++;
+ }
+
+ // Startup code that loops over the method names and puts handlers on the
+ // Object class to catch noSuchMethod invocations.
+ ClassElement objectClass = compiler.objectClass;
+ String createInvocationMirror = namer.isolateAccess(
+ backend.getCreateInvocationMirror());
+ String noSuchMethodName = namer.publicInstanceMethodNameByArity(
+ Compiler.NO_SUCH_METHOD, Compiler.NO_SUCH_METHOD_ARG_COUNT);
+ var type = 0;
+ if (useDiffEncoding) {
+ statements.addAll([
+ js('var objectClassObject = '
+ ' collectedClasses["${namer.getNameOfClass(objectClass)}"],'
+ ' shortNames = "$diffEncoding".split(","),'
+ ' nameNumber = 0,'
+ ' diffEncodedString = shortNames[0],'
+ ' calculatedShortNames = [0, 1]'), // 0, 1 are args for splice.
+ js.if_('objectClassObject instanceof Array',
+ js('objectClassObject = objectClassObject[1]')),
+ js.for_('var i = 0', 'i < diffEncodedString.length', 'i++', [
+ js('var codes = [],'
+ ' diff = 0,'
+ ' digit = diffEncodedString.charCodeAt(i)'),
+ js.if_('digit == ${$PERIOD}', [
+ js('nameNumber = 0'),
+ js('digit = diffEncodedString.charCodeAt(++i)')
+ ]),
+ js.while_('digit <= ${$Z}', [
+ js('diff *= 26'),
+ js('diff += (digit - ${$A})'),
+ js('digit = diffEncodedString.charCodeAt(++i)')
+ ]),
+ js('diff *= 26'),
+ js('diff += (digit - ${$a})'),
+ js('nameNumber += diff'),
+ js.for_('var remaining = nameNumber',
+ 'remaining > 0',
+ 'remaining = (remaining / 88) | 0', [
+ js('codes.unshift(${$HASH} + remaining % 88)')
+ ]),
+ js('calculatedShortNames.push('
+ ' String.fromCharCode.apply(String, codes))')
+ ]),
+ js('shortNames.splice.apply(shortNames, calculatedShortNames)')
+ ]);
+ } else {
+ // No useDiffEncoding version.
+ Iterable<String> longs = trivialNsmHandlers.map((selector) =>
+ selector.invocationMirrorMemberName);
+ String longNamesConstant = minify ? "" :
+ ',longNames = "${longs.join(",")}".split(",")';
+ statements.add(
+ js('var objectClassObject = '
+ ' collectedClasses["${namer.getNameOfClass(objectClass)}"],'
+ ' shortNames = "$diffEncoding".split(",")'
+ ' $longNamesConstant'));
+ statements.add(
+ js.if_('objectClassObject instanceof Array',
+ js('objectClassObject = objectClassObject[1]')));
+ }
+
+ String sliceOffset = ', (j < $firstNormalSelector) ? 1 : 0';
+ if (firstNormalSelector == 0) sliceOffset = '';
+ if (firstNormalSelector == shorts.length) sliceOffset = ', 1';
+
+ String whatToPatch = task.nativeEmitter.handleNoSuchMethod ?
+ "Object.prototype" :
+ "objectClassObject";
+
+ var params = ['name', 'short', 'type'];
+ var sliceOffsetParam = '';
+ var slice = 'Array.prototype.slice.call';
+ if (!sliceOffset.isEmpty) {
+ sliceOffsetParam = ', sliceOffset';
+ params.add('sliceOffset');
+ }
+ statements.addAll([
+ js.for_('var j = 0', 'j < shortNames.length', 'j++', [
+ js('var type = 0'),
+ js('var short = shortNames[j]'),
+ js.if_('short[0] == "${namer.getterPrefix[0]}"', js('type = 1')),
+ js.if_('short[0] == "${namer.setterPrefix[0]}"', js('type = 2')),
+ // Generate call to:
+ // createInvocationMirror(String name, internalName, type, arguments,
+ // argumentNames)
+ js('$whatToPatch[short] = #(${minify ? "shortNames" : "longNames"}[j], '
+ 'short, type$sliceOffset)',
+ js.fun(params, [js.return_(js.fun([],
+ [js.return_(js(
+ 'this.$noSuchMethodName('
+ 'this, '
+ '$createInvocationMirror('
+ 'name, short, type, '
+ '$slice(arguments$sliceOffsetParam), []))'))]))]))
+ ])
+ ]);
+ }
+}
diff --git a/sdk/lib/_internal/compiler/implementation/js_emitter/type_test_emitter.dart b/sdk/lib/_internal/compiler/implementation/js_emitter/type_test_emitter.dart
new file mode 100644
index 0000000..90829b8
--- /dev/null
+++ b/sdk/lib/_internal/compiler/implementation/js_emitter/type_test_emitter.dart
@@ -0,0 +1,423 @@
+// 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 dart2js.js_emitter;
+
+class TypeTestEmitter extends CodeEmitterHelper {
+ static const int MAX_FUNCTION_TYPE_PREDICATES = 10;
+
+ /**
+ * Raw ClassElement symbols occuring in is-checks and type assertions. If the
+ * program contains parameterized checks `x is Set<int>` and
+ * `x is Set<String>` then the ClassElement `Set` will occur once in
+ * [checkedClasses].
+ */
+ Set<ClassElement> checkedClasses;
+
+ /**
+ * The set of function types that checked, both explicity through tests of
+ * typedefs and implicitly through type annotations in checked mode.
+ */
+ Set<FunctionType> checkedFunctionTypes;
+
+ Map<ClassElement, Set<FunctionType>> checkedGenericFunctionTypes =
+ new Map<ClassElement, Set<FunctionType>>();
+
+ Set<FunctionType> checkedNonGenericFunctionTypes =
+ new Set<FunctionType>();
+
+ final Set<ClassElement> rtiNeededClasses = new Set<ClassElement>();
+
+ Iterable<ClassElement> cachedClassesUsingTypeVariableTests;
+
+ Iterable<ClassElement> get classesUsingTypeVariableTests {
+ if (cachedClassesUsingTypeVariableTests == null) {
+ cachedClassesUsingTypeVariableTests = compiler.codegenWorld.isChecks
+ .where((DartType t) => t is TypeVariableType)
+ .map((TypeVariableType v) => v.element.getEnclosingClass())
+ .toList();
+ }
+ return cachedClassesUsingTypeVariableTests;
+ }
+
+ void emitIsTests(ClassElement classElement, ClassBuilder builder) {
+ assert(invariant(classElement, classElement.isDeclaration));
+
+ void generateIsTest(Element other) {
+ if (other == compiler.objectClass && other != classElement) {
+ // Avoid emitting [:$isObject:] on all classes but [Object].
+ return;
+ }
+ other = backend.getImplementationClass(other);
+ builder.addProperty(namer.operatorIs(other), js('true'));
+ }
+
+ void generateIsFunctionTypeTest(FunctionType type) {
+ String operator = namer.operatorIsType(type);
+ builder.addProperty(operator, new jsAst.LiteralBool(true));
+ }
+
+ void generateFunctionTypeSignature(Element method, FunctionType type) {
+ assert(method.isImplementation);
+ jsAst.Expression thisAccess = new jsAst.This();
+ Node node = method.parseNode(compiler);
+ ClosureClassMap closureData =
+ compiler.closureToClassMapper.closureMappingCache[node];
+ if (closureData != null) {
+ Element thisElement =
+ closureData.freeVariableMapping[closureData.thisElement];
+ if (thisElement != null) {
+ assert(thisElement.hasFixedBackendName());
+ String thisName = thisElement.fixedBackendName();
+ thisAccess = js('this')[js.string(thisName)];
+ }
+ }
+ RuntimeTypes rti = backend.rti;
+ jsAst.Expression encoding = rti.getSignatureEncoding(type, thisAccess);
+ String operatorSignature = namer.operatorSignature();
+ builder.addProperty(operatorSignature, encoding);
+ }
+
+ void generateSubstitution(ClassElement cls, {bool emitNull: false}) {
+ if (cls.typeVariables.isEmpty) return;
+ RuntimeTypes rti = backend.rti;
+ jsAst.Expression expression;
+ bool needsNativeCheck = task.nativeEmitter.requiresNativeIsCheck(cls);
+ expression = rti.getSupertypeSubstitution(
+ classElement, cls, alwaysGenerateFunction: true);
+ if (expression == null && (emitNull || needsNativeCheck)) {
+ expression = new jsAst.LiteralNull();
+ }
+ if (expression != null) {
+ builder.addProperty(namer.substitutionName(cls), expression);
+ }
+ }
+
+ generateIsTestsOn(classElement, generateIsTest,
+ generateIsFunctionTypeTest, generateFunctionTypeSignature,
+ generateSubstitution);
+ }
+
+ /**
+ * Generate "is tests" for [cls]: itself, and the "is tests" for the
+ * classes it implements and type argument substitution functions for these
+ * tests. We don't need to add the "is tests" of the super class because
+ * they will be inherited at runtime, but we may need to generate the
+ * substitutions, because they may have changed.
+ */
+ void generateIsTestsOn(ClassElement cls,
+ void emitIsTest(Element element),
+ FunctionTypeTestEmitter emitIsFunctionTypeTest,
+ FunctionTypeSignatureEmitter emitFunctionTypeSignature,
+ SubstitutionEmitter emitSubstitution) {
+ if (checkedClasses.contains(cls)) {
+ emitIsTest(cls);
+ emitSubstitution(cls);
+ }
+
+ RuntimeTypes rti = backend.rti;
+ ClassElement superclass = cls.superclass;
+
+ bool haveSameTypeVariables(ClassElement a, ClassElement b) {
+ if (a.isClosure()) return true;
+ if (b.isUnnamedMixinApplication) {
+ return false;
+ }
+ return a.typeVariables == b.typeVariables;
+ }
+
+ if (superclass != null && superclass != compiler.objectClass &&
+ !haveSameTypeVariables(cls, superclass)) {
+ // We cannot inherit the generated substitutions, because the type
+ // variable layout for this class is different. Instead we generate
+ // substitutions for all checks and make emitSubstitution a NOP for the
+ // rest of this function.
+ Set<ClassElement> emitted = new Set<ClassElement>();
+ // TODO(karlklose): move the computation of these checks to
+ // RuntimeTypeInformation.
+ if (backend.classNeedsRti(cls)) {
+ emitSubstitution(superclass, emitNull: true);
+ emitted.add(superclass);
+ }
+ for (DartType supertype in cls.allSupertypes) {
+ ClassElement superclass = supertype.element;
+ if (classesUsingTypeVariableTests.contains(superclass)) {
+ emitSubstitution(superclass, emitNull: true);
+ emitted.add(superclass);
+ }
+ for (ClassElement check in checkedClasses) {
+ if (supertype.element == check && !emitted.contains(check)) {
+ // Generate substitution. If no substitution is necessary, emit
+ // [:null:] to overwrite a (possibly) existing substitution from the
+ // super classes.
+ emitSubstitution(check, emitNull: true);
+ emitted.add(check);
+ }
+ }
+ }
+ void emitNothing(_, {emitNull}) {};
+ emitSubstitution = emitNothing;
+ }
+
+ Set<Element> generated = new Set<Element>();
+ // A class that defines a [:call:] method implicitly implements
+ // [Function] and needs checks for all typedefs that are used in is-checks.
+ if (checkedClasses.contains(compiler.functionClass) ||
+ !checkedFunctionTypes.isEmpty) {
+ Element call = cls.lookupLocalMember(Compiler.CALL_OPERATOR_NAME);
+ if (call == null) {
+ // If [cls] is a closure, it has a synthetic call operator method.
+ call = cls.lookupBackendMember(Compiler.CALL_OPERATOR_NAME);
+ }
+ if (call != null && call.isFunction()) {
+ generateInterfacesIsTests(compiler.functionClass,
+ emitIsTest,
+ emitSubstitution,
+ generated);
+ FunctionType callType = call.computeType(compiler);
+ Map<FunctionType, bool> functionTypeChecks =
+ getFunctionTypeChecksOn(callType);
+ generateFunctionTypeTests(
+ call, callType, functionTypeChecks,
+ emitFunctionTypeSignature, emitIsFunctionTypeTest);
+ }
+ }
+
+ for (DartType interfaceType in cls.interfaces) {
+ generateInterfacesIsTests(interfaceType.element, emitIsTest,
+ emitSubstitution, generated);
+ }
+ }
+
+ /**
+ * Generate "is tests" where [cls] is being implemented.
+ */
+ void generateInterfacesIsTests(ClassElement cls,
+ void emitIsTest(ClassElement element),
+ SubstitutionEmitter emitSubstitution,
+ Set<Element> alreadyGenerated) {
+ void tryEmitTest(ClassElement check) {
+ if (!alreadyGenerated.contains(check) && checkedClasses.contains(check)) {
+ alreadyGenerated.add(check);
+ emitIsTest(check);
+ emitSubstitution(check);
+ }
+ };
+
+ tryEmitTest(cls);
+
+ for (DartType interfaceType in cls.interfaces) {
+ Element element = interfaceType.element;
+ tryEmitTest(element);
+ generateInterfacesIsTests(element, emitIsTest, emitSubstitution,
+ alreadyGenerated);
+ }
+
+ // We need to also emit "is checks" for the superclass and its supertypes.
+ ClassElement superclass = cls.superclass;
+ if (superclass != null) {
+ tryEmitTest(superclass);
+ generateInterfacesIsTests(superclass, emitIsTest, emitSubstitution,
+ alreadyGenerated);
+ }
+ }
+
+ /**
+ * Returns a mapping containing all checked function types for which [type]
+ * can be a subtype. A function type is mapped to [:true:] if [type] is
+ * statically known to be a subtype of it and to [:false:] if [type] might
+ * be a subtype, provided with the right type arguments.
+ */
+ // TODO(johnniwinther): Change to return a mapping from function types to
+ // a set of variable points and use this to detect statically/dynamically
+ // known subtype relations.
+ Map<FunctionType, bool> getFunctionTypeChecksOn(DartType type) {
+ Map<FunctionType, bool> functionTypeMap =
+ new LinkedHashMap<FunctionType, bool>();
+ for (FunctionType functionType in checkedFunctionTypes) {
+ if (compiler.types.isSubtype(type, functionType)) {
+ functionTypeMap[functionType] = true;
+ } else if (compiler.types.isPotentialSubtype(type, functionType)) {
+ functionTypeMap[functionType] = false;
+ }
+ }
+ // TODO(johnniwinther): Ensure stable ordering of the keys.
+ return functionTypeMap;
+ }
+
+ /**
+ * Generates function type checks on [method] with type [methodType] against
+ * the function type checks in [functionTypeChecks].
+ */
+ void generateFunctionTypeTests(
+ Element method,
+ FunctionType methodType,
+ Map<FunctionType, bool> functionTypeChecks,
+ FunctionTypeSignatureEmitter emitFunctionTypeSignature,
+ FunctionTypeTestEmitter emitIsFunctionTypeTest) {
+ bool hasDynamicFunctionTypeCheck = false;
+ int neededPredicates = 0;
+ functionTypeChecks.forEach((FunctionType functionType, bool knownSubtype) {
+ if (!knownSubtype) {
+ registerDynamicFunctionTypeCheck(functionType);
+ hasDynamicFunctionTypeCheck = true;
+ } else if (!backend.rti.isSimpleFunctionType(functionType)) {
+ // Simple function types are always checked using predicates and should
+ // not provoke generation of signatures.
+ neededPredicates++;
+ }
+ });
+ bool alwaysUseSignature = false;
+ if (hasDynamicFunctionTypeCheck ||
+ neededPredicates > MAX_FUNCTION_TYPE_PREDICATES) {
+ emitFunctionTypeSignature(method, methodType);
+ alwaysUseSignature = true;
+ }
+ functionTypeChecks.forEach((FunctionType functionType, bool knownSubtype) {
+ if (knownSubtype) {
+ if (backend.rti.isSimpleFunctionType(functionType)) {
+ // Simple function types are always checked using predicates.
+ emitIsFunctionTypeTest(functionType);
+ } else if (alwaysUseSignature) {
+ registerDynamicFunctionTypeCheck(functionType);
+ } else {
+ emitIsFunctionTypeTest(functionType);
+ }
+ }
+ });
+ }
+
+ void registerDynamicFunctionTypeCheck(FunctionType functionType) {
+ ClassElement classElement = Types.getClassContext(functionType);
+ if (classElement != null) {
+ checkedGenericFunctionTypes.putIfAbsent(classElement,
+ () => new Set<FunctionType>()).add(functionType);
+ } else {
+ checkedNonGenericFunctionTypes.add(functionType);
+ }
+ }
+
+ void emitRuntimeTypeSupport(CodeBuffer buffer) {
+ task.addComment('Runtime type support', buffer);
+ RuntimeTypes rti = backend.rti;
+ TypeChecks typeChecks = rti.requiredChecks;
+
+ // Add checks to the constructors of instantiated classes.
+ for (ClassElement cls in typeChecks) {
+ // TODO(9556). The properties added to 'holder' should be generated
+ // directly as properties of the class object, not added later.
+ String holder = namer.isolateAccess(backend.getImplementationClass(cls));
+ for (TypeCheck check in typeChecks[cls]) {
+ ClassElement cls = check.cls;
+ buffer.write('$holder.${namer.operatorIs(cls)}$_=${_}true$N');
+ Substitution substitution = check.substitution;
+ if (substitution != null) {
+ CodeBuffer body =
+ jsAst.prettyPrint(substitution.getCode(rti, false), compiler);
+ buffer.write('$holder.${namer.substitutionName(cls)}$_=${_}');
+ buffer.write(body);
+ buffer.write('$N');
+ }
+ };
+ }
+
+ void addSignature(FunctionType type) {
+ jsAst.Expression encoding = rti.getTypeEncoding(type);
+ buffer.add('${namer.signatureName(type)}$_=${_}');
+ buffer.write(jsAst.prettyPrint(encoding, compiler));
+ buffer.add('$N');
+ }
+
+ checkedNonGenericFunctionTypes.forEach(addSignature);
+
+ checkedGenericFunctionTypes.forEach((_, Set<FunctionType> functionTypes) {
+ functionTypes.forEach(addSignature);
+ });
+ }
+
+ /**
+ * Returns the classes with constructors used as a 'holder' in
+ * [emitRuntimeTypeSupport].
+ * TODO(9556): Some cases will go away when the class objects are created as
+ * complete. Not all classes will go away while constructors are referenced
+ * from type substitutions.
+ */
+ Set<ClassElement> classesModifiedByEmitRuntimeTypeSupport() {
+ TypeChecks typeChecks = backend.rti.requiredChecks;
+ Set<ClassElement> result = new Set<ClassElement>();
+ for (ClassElement cls in typeChecks) {
+ for (TypeCheck check in typeChecks[cls]) {
+ result.add(backend.getImplementationClass(cls));
+ break;
+ }
+ }
+ return result;
+ }
+
+ Set<ClassElement> computeRtiNeededClasses() {
+ void addClassWithSuperclasses(ClassElement cls) {
+ rtiNeededClasses.add(cls);
+ for (ClassElement superclass = cls.superclass;
+ superclass != null;
+ superclass = superclass.superclass) {
+ rtiNeededClasses.add(superclass);
+ }
+ }
+
+ void addClassesWithSuperclasses(Iterable<ClassElement> classes) {
+ for (ClassElement cls in classes) {
+ addClassWithSuperclasses(cls);
+ }
+ }
+
+ // 1. Add classes that are referenced by type arguments or substitutions in
+ // argument checks.
+ // TODO(karlklose): merge this case with 2 when unifying argument and
+ // object checks.
+ RuntimeTypes rti = backend.rti;
+ rti.getRequiredArgumentClasses(backend).forEach((ClassElement c) {
+ // Types that we represent with JS native types (like int and String) do
+ // not need a class definition as we use the interceptor classes instead.
+ if (!rti.isJsNative(c)) {
+ addClassWithSuperclasses(c);
+ }
+ });
+
+ // 2. Add classes that are referenced by substitutions in object checks and
+ // their superclasses.
+ TypeChecks requiredChecks =
+ rti.computeChecks(rtiNeededClasses, checkedClasses);
+ Set<ClassElement> classesUsedInSubstitutions =
+ rti.getClassesUsedInSubstitutions(backend, requiredChecks);
+ addClassesWithSuperclasses(classesUsedInSubstitutions);
+
+ // 3. Add classes that contain checked generic function types. These are
+ // needed to store the signature encoding.
+ for (FunctionType type in checkedFunctionTypes) {
+ ClassElement contextClass = Types.getClassContext(type);
+ if (contextClass != null) {
+ rtiNeededClasses.add(contextClass);
+ }
+ }
+
+ return rtiNeededClasses;
+ }
+
+ void computeRequiredTypeChecks() {
+ assert(checkedClasses == null && checkedFunctionTypes == null);
+
+ backend.rti.addImplicitChecks(compiler.codegenWorld,
+ classesUsingTypeVariableTests);
+
+ checkedClasses = new Set<ClassElement>();
+ checkedFunctionTypes = new Set<FunctionType>();
+ compiler.codegenWorld.isChecks.forEach((DartType t) {
+ if (t is InterfaceType) {
+ checkedClasses.add(t.element);
+ } else if (t is FunctionType) {
+ checkedFunctionTypes.add(t);
+ }
+ });
+ }
+}
diff --git a/sdk/lib/_internal/compiler/implementation/library_loader.dart b/sdk/lib/_internal/compiler/implementation/library_loader.dart
index 1342ce8..85191f1 100644
--- a/sdk/lib/_internal/compiler/implementation/library_loader.dart
+++ b/sdk/lib/_internal/compiler/implementation/library_loader.dart
@@ -569,11 +569,13 @@
* the library dependency graph.
*/
class ExportLink {
+ final Export export;
final CombinatorFilter combinatorFilter;
final LibraryDependencyNode exportNode;
ExportLink(Export export, LibraryDependencyNode this.exportNode)
- : this.combinatorFilter = new CombinatorFilter.fromTag(export);
+ : this.export = export,
+ this.combinatorFilter = new CombinatorFilter.fromTag(export);
/**
* Exports [element] to the dependent library unless [element] is filtered by
@@ -582,7 +584,7 @@
*/
bool exportElement(Element element) {
if (combinatorFilter.exclude(element)) return false;
- return exportNode.addElementToPendingExports(element);
+ return exportNode.addElementToPendingExports(element, export);
}
}
@@ -622,12 +624,17 @@
Map<SourceString, Element> exportScope =
new LinkedHashMap<SourceString, Element>();
+ /// Map from exported elements to the export directives that exported them.
+ Map<Element, Link<Export>> exporters = new Map<Element, Link<Export>>();
+
/**
* The set of exported elements that need to be propageted to dependent
* libraries as part of the work-list computation performed in
- * [LibraryDependencyHandler.computeExports].
+ * [LibraryDependencyHandler.computeExports]. Each export element is mapped
+ * to a list of exports directives that export it.
*/
- Set<Element> pendingExportSet = new Set<Element>();
+ Map<Element, Link<Export>> pendingExportMap =
+ new Map<Element, Link<Export>>();
LibraryDependencyNode(LibraryElement this.library);
@@ -656,15 +663,21 @@
* the export scopes performed in [LibraryDependencyHandler.computeExports].
*/
void registerInitialExports() {
- pendingExportSet.addAll(library.getNonPrivateElementsInScope());
+ for (Element element in library.getNonPrivateElementsInScope()) {
+ pendingExportMap[element] = const Link<Export>();
+ }
}
void registerHandledExports(LibraryElement exportedLibraryElement,
+ Export export,
CombinatorFilter filter) {
assert(invariant(library, exportedLibraryElement.exportsHandled));
for (Element exportedElement in exportedLibraryElement.exports) {
if (!filter.exclude(exportedElement)) {
- pendingExportSet.add(exportedElement);
+ Link<Export> exports =
+ pendingExportMap.putIfAbsent(exportedElement,
+ () => const Link<Export>());
+ pendingExportMap[exportedElement] = exports.prepend(export);
}
}
}
@@ -688,9 +701,10 @@
/**
* Copies and clears pending export set for this node.
*/
- List<Element> pullPendingExports() {
- List<Element> pendingExports = new List.from(pendingExportSet);
- pendingExportSet.clear();
+ Map<Element, Link<Export>> pullPendingExports() {
+ Map<Element, Link<Export>> pendingExports =
+ new Map<Element, Link<Export>>.from(pendingExportMap);
+ pendingExportMap.clear();
return pendingExports;
}
@@ -698,25 +712,64 @@
* Adds [element] to the export scope for this node. If the [element] name
* is a duplicate, an error element is inserted into the export scope.
*/
- Element addElementToExportScope(Compiler compiler, Element element) {
+ Element addElementToExportScope(Compiler compiler, Element element,
+ Link<Export> exports) {
SourceString name = element.name;
+
+ void reportDuplicateExport(Element duplicate,
+ Link<Export> duplicateExports,
+ {bool reportError: true}) {
+ assert(invariant(library, !duplicateExports.isEmpty,
+ message: "No export for $duplicate from ${duplicate.getLibrary()} "
+ "in $library."));
+ compiler.withCurrentElement(library, () {
+ for (Export export in duplicateExports) {
+ if (reportError) {
+ compiler.reportError(export,
+ MessageKind.DUPLICATE_EXPORT, {'name': name});
+ reportError = false;
+ } else {
+ compiler.reportInfo(export,
+ MessageKind.DUPLICATE_EXPORT_CONT, {'name': name});
+ }
+ }
+ });
+ }
+
+ void reportDuplicateExportDecl(Element duplicate,
+ Link<Export> duplicateExports) {
+ assert(invariant(library, !duplicateExports.isEmpty,
+ message: "No export for $duplicate from ${duplicate.getLibrary()} "
+ "in $library."));
+ compiler.reportInfo(duplicate, MessageKind.DUPLICATE_EXPORT_DECL,
+ {'name': name, 'uriString': duplicateExports.head.uri});
+ }
+
Element existingElement = exportScope[name];
- if (existingElement != null) {
+ if (existingElement != null && existingElement != element) {
if (existingElement.isErroneous()) {
- compiler.reportError(element, MessageKind.DUPLICATE_EXPORT,
- {'name': name});
+ reportDuplicateExport(element, exports);
+ reportDuplicateExportDecl(element, exports);
element = existingElement;
- } else if (existingElement.getLibrary() != library) {
+ } else if (existingElement.getLibrary() == library) {
+ // Do nothing. [existingElement] hides [element].
+ } else if (element.getLibrary() == library) {
+ // [element] hides [existingElement].
+ exportScope[name] = element;
+ exporters[element] = exports;
+ } else {
// Declared elements hide exported elements.
- compiler.reportError(existingElement, MessageKind.DUPLICATE_EXPORT,
- {'name': name});
- compiler.reportError(element, MessageKind.DUPLICATE_EXPORT,
- {'name': name});
+ Link<Export> existingExports = exporters[existingElement];
+ reportDuplicateExport(existingElement, existingExports);
+ reportDuplicateExport(element, exports, reportError: false);
+ reportDuplicateExportDecl(existingElement, existingExports);
+ reportDuplicateExportDecl(element, exports);
element = exportScope[name] = new ErroneousElementX(
MessageKind.DUPLICATE_EXPORT, {'name': name}, name, library);
}
} else {
exportScope[name] = element;
+ exporters[element] = exports;
}
return element;
}
@@ -741,14 +794,16 @@
* the pending export set was modified. The combinators of [export] are used
* to filter the element.
*/
- bool addElementToPendingExports(Element element) {
+ bool addElementToPendingExports(Element element, Export export) {
+ bool changed = false;
if (!identical(exportScope[element.name], element)) {
- if (!pendingExportSet.contains(element)) {
- pendingExportSet.add(element);
- return true;
- }
+ Link<Export> exports = pendingExportMap.putIfAbsent(element, () {
+ changed = true;
+ return const Link<Export>();
+ });
+ pendingExportMap[element] = exports.prepend(export);
}
- return false;
+ return changed;
}
}
@@ -783,8 +838,8 @@
bool changed = true;
while (changed) {
changed = false;
- Map<LibraryDependencyNode, List<Element>> tasks =
- new LinkedHashMap<LibraryDependencyNode, List<Element>>();
+ Map<LibraryDependencyNode, Map<Element, Link<Export>>> tasks =
+ new Map<LibraryDependencyNode, Map<Element, Link<Export>>>();
// Locally defined elements take precedence over exported
// elements. So we must propagate local elements first. We
@@ -792,12 +847,13 @@
// propagating. This enforces that we handle exports
// breadth-first, with locally defined elements being level 0.
nodeMap.forEach((_, LibraryDependencyNode node) {
- List<Element> pendingExports = node.pullPendingExports();
+ Map<Element, Link<Export>> pendingExports = node.pullPendingExports();
tasks[node] = pendingExports;
});
- tasks.forEach((LibraryDependencyNode node, List<Element> pendingExports) {
- pendingExports.forEach((Element element) {
- element = node.addElementToExportScope(compiler, element);
+ tasks.forEach((LibraryDependencyNode node,
+ Map<Element, Link<Export>> pendingExports) {
+ pendingExports.forEach((Element element, Link<Export> exports) {
+ element = node.addElementToExportScope(compiler, element, exports);
if (node.propagateElement(element)) {
changed = true;
}
@@ -833,7 +889,8 @@
if (loadedLibrary.exportsHandled) {
// Export scope already computed on [loadedLibrary].
var combinatorFilter = new CombinatorFilter.fromTag(tag);
- exportingNode.registerHandledExports(loadedLibrary, combinatorFilter);
+ exportingNode.registerHandledExports(
+ loadedLibrary, tag, combinatorFilter);
return;
}
LibraryDependencyNode exportedNode = nodeMap[loadedLibrary];
diff --git a/sdk/lib/_internal/compiler/implementation/native_handler.dart b/sdk/lib/_internal/compiler/implementation/native_handler.dart
index e475aa7..f16461b 100644
--- a/sdk/lib/_internal/compiler/implementation/native_handler.dart
+++ b/sdk/lib/_internal/compiler/implementation/native_handler.dart
@@ -797,7 +797,7 @@
}
for (final typeString in specString.split('|')) {
var type = _parseType(typeString, compiler,
- (name) => resolver.resolveTypeFromString(name),
+ (name) => resolver.resolveTypeFromString(specLiteral, name),
jsCall);
behavior.typesInstantiated.add(type);
behavior.typesReturned.add(type);
diff --git a/sdk/lib/_internal/compiler/implementation/patch_parser.dart b/sdk/lib/_internal/compiler/implementation/patch_parser.dart
index 88da806..fcd0be2 100644
--- a/sdk/lib/_internal/compiler/implementation/patch_parser.dart
+++ b/sdk/lib/_internal/compiler/implementation/patch_parser.dart
@@ -145,10 +145,6 @@
// Patch elements are stored on the patched functions or classes.
scanLibraryElements(patchLibrary.entryCompilationUnit, imports);
});
- // After scanning declarations, we handle the import tags in the patch.
- // TODO(lrn): These imports end up in the original library and are in
- // scope for the original methods too. This should be fixed.
- compiler.importHelperLibrary(originLibrary);
// TODO(rnystrom): Remove .toList() here if #11523 is fixed.
return Future.forEach(imports.toLink().toList(), (tag) {
return compiler.withCurrentElement(patchLibrary, () {
diff --git a/sdk/lib/_internal/compiler/implementation/resolution/members.dart b/sdk/lib/_internal/compiler/implementation/resolution/members.dart
index af4208d..f09879a 100644
--- a/sdk/lib/_internal/compiler/implementation/resolution/members.dart
+++ b/sdk/lib/_internal/compiler/implementation/resolution/members.dart
@@ -469,12 +469,15 @@
visitor.useElement(tree, element);
SendSet send = tree.asSendSet();
+ Modifiers modifiers = element.modifiers;
if (send != null) {
// TODO(johnniwinther): Avoid analyzing initializers if
// [Compiler.analyzeSignaturesOnly] is set.
visitor.visit(send.arguments.head);
- } else if (element.modifiers.isConst()) {
+ } else if (modifiers.isConst()) {
compiler.reportError(element, MessageKind.CONST_WITHOUT_INITIALIZER);
+ } else if (modifiers.isFinal() && !element.isInstanceMember()) {
+ compiler.reportError(element, MessageKind.FINAL_WITHOUT_INITIALIZER);
}
if (Elements.isStaticOrTopLevelField(element)) {
@@ -1531,10 +1534,10 @@
TypeResolver(this.compiler);
Element resolveTypeName(Scope scope,
- SourceString prefixName,
+ Identifier prefixName,
Identifier typeName) {
if (prefixName != null) {
- Element e = scope.lookup(prefixName);
+ Element e = lookupInScope(compiler, prefixName, scope, prefixName.source);
if (e != null) {
if (identical(e.kind, ElementKind.PREFIX)) {
// The receiver is a prefix. Lookup in the imported members.
@@ -1556,7 +1559,7 @@
} else if (identical(stringValue, 'dynamic')) {
return compiler.dynamicClass;
} else {
- return scope.lookup(typeName.source);
+ return lookupInScope(compiler, typeName, scope, typeName.source);
}
}
}
@@ -1564,11 +1567,11 @@
DartType resolveTypeAnnotation(MappingVisitor visitor, TypeAnnotation node,
{bool malformedIsError: false}) {
Identifier typeName;
- SourceString prefixName;
+ Identifier prefixName;
Send send = node.typeName.asSend();
if (send != null) {
// The type name is of the form [: prefix . identifier :].
- prefixName = send.receiver.asIdentifier().source;
+ prefixName = send.receiver.asIdentifier();
typeName = send.selector.asIdentifier();
} else {
typeName = node.typeName.asIdentifier();
@@ -1838,6 +1841,11 @@
int allowedCategory = ElementCategory.VARIABLE | ElementCategory.FUNCTION
| ElementCategory.IMPLIES_TYPE;
+ /// When visiting the type declaration of the variable in a [ForIn] loop,
+ /// the initializer of the variable is implicit and we should not emit an
+ /// error when verifying that all final variables are initialized.
+ bool allowFinalWithoutInitializer = false;
+
// TODO(ahe): Find a way to share this with runtime implementation.
static final RegExp symbolValidationPattern =
new RegExp(r'^(?:[a-zA-Z$][a-zA-Z$0-9_]*\.)*(?:[a-zA-Z$][a-zA-Z$0-9_]*=?|'
@@ -1964,7 +1972,7 @@
return null;
} else {
SourceString name = node.source;
- Element element = scope.lookup(name);
+ Element element = lookupInScope(compiler, node, scope, name);
if (Elements.isUnresolved(element) && name.slowToString() == 'dynamic') {
element = compiler.dynamicClass;
}
@@ -2519,8 +2527,9 @@
}
/// Callback for native enqueuer to parse a type. Returns [:null:] on error.
- DartType resolveTypeFromString(String typeName) {
- Element element = scope.lookup(new SourceString(typeName));
+ DartType resolveTypeFromString(Node node, String typeName) {
+ Element element = lookupInScope(compiler, node,
+ scope, new SourceString(typeName));
if (element == null) return null;
if (element is! ClassElement) return null;
ClassElement cls = element;
@@ -3080,7 +3089,11 @@
visit(node.expression);
Scope blockScope = new BlockScope(scope);
Node declaration = node.declaredIdentifier;
+
+ bool oldAllowFinalWithoutInitializer = allowFinalWithoutInitializer;
+ allowFinalWithoutInitializer = true;
visitIn(declaration, blockScope);
+ allowFinalWithoutInitializer = oldAllowFinalWithoutInitializer;
Send send = declaration.asSend();
VariableDefinitions variableDefinitions =
@@ -3990,7 +4003,7 @@
}
void visitIdentifier(Identifier node) {
- Element element = context.lookup(node.source);
+ Element element = lookupInScope(compiler, node, context, node.source);
if (element == null) {
compiler.reportError(
node, MessageKind.CANNOT_RESOLVE_TYPE.error, {'typeName': node});
@@ -4011,7 +4024,7 @@
error(node.receiver, MessageKind.NOT_A_PREFIX, {'node': node.receiver});
return;
}
- Element element = context.lookup(prefix.source);
+ Element element = lookupInScope(compiler, prefix, context, prefix.source);
if (element == null || !identical(element.kind, ElementKind.PREFIX)) {
error(node.receiver, MessageKind.NOT_A_PREFIX, {'node': node.receiver});
return;
@@ -4062,6 +4075,10 @@
if (definitions.modifiers.isConst()) {
compiler.reportError(node, MessageKind.CONST_WITHOUT_INITIALIZER);
}
+ if (definitions.modifiers.isFinal() &&
+ !resolver.allowFinalWithoutInitializer) {
+ compiler.reportError(node, MessageKind.FINAL_WITHOUT_INITIALIZER);
+ }
return node.source;
}
@@ -4476,7 +4493,7 @@
Element visitIdentifier(Identifier node) {
SourceString name = node.source;
Element e = resolver.reportLookupErrorIfAny(
- resolver.scope.lookup(name), node, name);
+ lookupInScope(compiler, node, resolver.scope, name), node, name);
// TODO(johnniwinther): Change errors to warnings, cf. 11.11.1.
if (e == null) {
return failOrReturnErroneousElement(resolver.enclosingElement, node, name,
@@ -4504,3 +4521,9 @@
expression, expression);
}
}
+
+/// Looks up [name] in [scope] and unwraps the result.
+Element lookupInScope(Compiler compiler, Node node,
+ Scope scope, SourceString name) {
+ return Elements.unwrap(scope.lookup(name), compiler, node);
+}
diff --git a/sdk/lib/_internal/compiler/implementation/scanner/token.dart b/sdk/lib/_internal/compiler/implementation/scanner/token.dart
index bda4b76..53a1f08 100644
--- a/sdk/lib/_internal/compiler/implementation/scanner/token.dart
+++ b/sdk/lib/_internal/compiler/implementation/scanner/token.dart
@@ -99,7 +99,7 @@
*/
Token next;
- Token(PrecedenceInfo this.info, int this.charOffset);
+ Token(this.info, this.charOffset);
get value => info.value;
diff --git a/sdk/lib/_internal/compiler/implementation/ssa/builder.dart b/sdk/lib/_internal/compiler/implementation/ssa/builder.dart
index 70713da..60bb2ad 100644
--- a/sdk/lib/_internal/compiler/implementation/ssa/builder.dart
+++ b/sdk/lib/_internal/compiler/implementation/ssa/builder.dart
@@ -275,6 +275,8 @@
// classes, or the same as [:this:] for non-intercepted classes.
ClassElement cls = element.getEnclosingClass();
JavaScriptBackend backend = compiler.backend;
+ bool isNativeUpgradeFactory = element.isGenerativeConstructor()
+ && Elements.isNativeOrExtendsNative(cls);
if (backend.isInterceptedMethod(element)) {
bool isInterceptorClass = backend.isInterceptorClass(cls.declaration);
SourceString name = isInterceptorClass
@@ -291,6 +293,14 @@
directLocals[closureData.thisElement] = value;
}
value.instructionType = builder.getTypeOfThis();
+ } else if (isNativeUpgradeFactory) {
+ bool isInterceptorClass = backend.isInterceptorClass(cls.declaration);
+ Element parameter = new InterceptedElement(
+ cls.computeType(compiler), const SourceString('receiver'), element);
+ HParameterValue value = new HParameterValue(parameter);
+ builder.graph.explicitReceiverParameter = value;
+ builder.graph.entry.addAtEntry(value);
+ value.instructionType = builder.getTypeOfThis();
}
}
@@ -1267,6 +1277,13 @@
}
}
+ // Generative constructors of native classes should not be called directly
+ // and have an extra argument that causes problems with inlining.
+ if (element.isGenerativeConstructor()
+ && Elements.isNativeOrExtendsNative(element.getEnclosingClass())) {
+ return false;
+ }
+
// A generative constructor body is not seen by global analysis,
// so we should not query for its type.
if (!element.isGenerativeConstructorBody()) {
@@ -1586,9 +1603,13 @@
TreeElements definitions = compiler.analyzeElement(member);
Node node = member.parseNode(compiler);
SendSet assignment = node.asSendSet();
- HInstruction value;
if (assignment == null) {
- value = graph.addConstantNull(compiler);
+ // Unassigned fields of native classes are not initialized to
+ // prevent overwriting pre-initialized native properties.
+ if (!Elements.isNativeOrExtendsNative(classElement)) {
+ HInstruction value = graph.addConstantNull(compiler);
+ fieldValues[member] = value;
+ }
} else {
Node right = assignment.arguments.head;
TreeElements savedElements = elements;
@@ -1599,9 +1620,9 @@
member, node, elements);
inlinedFrom(member, () => right.accept(this));
elements = savedElements;
- value = pop();
+ HInstruction value = pop();
+ fieldValues[member] = value;
}
- fieldValues[member] = value;
});
});
}
@@ -1619,6 +1640,8 @@
functionElement = functionElement.implementation;
ClassElement classElement =
functionElement.getEnclosingClass().implementation;
+ bool isNativeUpgradeFactory =
+ Elements.isNativeOrExtendsNative(classElement);
FunctionExpression function = functionElement.parseNode(compiler);
// Note that constructors (like any other static function) do not need
// to deal with optional arguments. It is the callers job to provide all
@@ -1654,10 +1677,20 @@
// Call the JavaScript constructor with the fields as argument.
List<HInstruction> constructorArguments = <HInstruction>[];
+ List<Element> fields = <Element>[];
+
classElement.forEachInstanceField(
(ClassElement enclosingClass, Element member) {
- constructorArguments.add(potentiallyCheckType(
- fieldValues[member], member.computeType(compiler)));
+ HInstruction value = fieldValues[member];
+ if (value == null) {
+ // Uninitialized native fields are pre-initialized by the native
+ // implementation.
+ assert(isNativeUpgradeFactory);
+ } else {
+ fields.add(member);
+ constructorArguments.add(
+ potentiallyCheckType(value, member.computeType(compiler)));
+ }
},
includeSuperAndInjectedMembers: true);
@@ -1668,11 +1701,25 @@
if (!currentInlinedInstantiations.isEmpty) {
instantiatedTypes = new List<DartType>.from(currentInlinedInstantiations);
}
- HForeignNew newObject = new HForeignNew(classElement,
- ssaType,
- constructorArguments,
- instantiatedTypes);
- add(newObject);
+
+ HInstruction newObject;
+ if (!isNativeUpgradeFactory) {
+ newObject = new HForeignNew(classElement,
+ ssaType,
+ constructorArguments,
+ instantiatedTypes);
+ add(newObject);
+ } else {
+ // Bulk assign to the initialized fields.
+ newObject = graph.explicitReceiverParameter;
+ // Null guard ensures an error if we are being called from an explicit
+ // 'new' of the constructor instead of via an upgrade. It is optimized out
+ // if there are field initializers.
+ add(new HFieldGet(null, newObject, isAssignable: false));
+ for (int i = 0; i < fields.length; i++) {
+ add(new HFieldSet(fields[i], newObject, constructorArguments[i]));
+ }
+ }
removeInlinedInstantiation(type);
// Create the runtime type information, if needed.
if (backend.classNeedsRti(classElement)) {
@@ -1684,12 +1731,22 @@
}
// Generate calls to the constructor bodies.
+ HInstruction interceptor = null;
for (int index = constructors.length - 1; index >= 0; index--) {
FunctionElement constructor = constructors[index];
assert(invariant(functionElement, constructor.isImplementation));
ConstructorBodyElement body = getConstructorBody(constructor);
if (body == null) continue;
+
List bodyCallInputs = <HInstruction>[];
+ if (isNativeUpgradeFactory) {
+ if (interceptor == null) {
+ Constant constant = new InterceptorConstant(
+ classElement.computeType(compiler));
+ interceptor = graph.addConstant(constant, compiler);
+ }
+ bodyCallInputs.add(interceptor);
+ }
bodyCallInputs.add(newObject);
TreeElements elements =
compiler.enqueuer.resolution.getCachedElements(constructor);
@@ -1697,7 +1754,6 @@
ClosureClassMap parameterClosureData =
compiler.closureToClassMapper.getMappingForNestedFunction(node);
-
FunctionSignature functionSignature = body.computeSignature(compiler);
// Provide the parameters to the generative constructor body.
functionSignature.orderedForEachParameter((parameter) {
@@ -1724,7 +1780,8 @@
bodyCallInputs.add(localsHandler.readLocal(scopeData.boxElement));
}
- if (tryInlineMethod(body, null, bodyCallInputs, function)) {
+ if (!isNativeUpgradeFactory && // TODO(13836): Fix inlining.
+ tryInlineMethod(body, null, bodyCallInputs, function)) {
pop();
} else {
HInvokeConstructorBody invoke =
@@ -2715,11 +2772,11 @@
}
stack.add(value);
} else if (Elements.isErroneousElement(element)) {
+ List<HInstruction> arguments =
+ send == null ? const <HInstruction>[] : <HInstruction>[value];
// An erroneous element indicates an unresolved static setter.
- generateThrowNoSuchMethod(
- location,
- getTargetName(element, 'set'),
- argumentNodes: (send == null ? const Link<Node>() : send.arguments));
+ generateThrowNoSuchMethod(location, getTargetName(element, 'set'),
+ argumentValues: arguments);
} else {
stack.add(value);
// If the value does not already have a name, give it here.
@@ -3565,6 +3622,11 @@
}
var inputs = <HInstruction>[];
+ if (constructor.isGenerativeConstructor() &&
+ Elements.isNativeOrExtendsNative(constructor.getEnclosingClass())) {
+ // Native class generative constructors take a pre-constructed object.
+ inputs.add(graph.addConstantNull(compiler));
+ }
// TODO(5347): Try to avoid the need for calling [implementation] before
// calling [addStaticSendArgumentsToList].
bool succeeded = addStaticSendArgumentsToList(selector, send.arguments,
diff --git a/sdk/lib/_internal/compiler/implementation/ssa/codegen.dart b/sdk/lib/_internal/compiler/implementation/ssa/codegen.dart
index 7b0b1a1..d0e882fd2 100644
--- a/sdk/lib/_internal/compiler/implementation/ssa/codegen.dart
+++ b/sdk/lib/_internal/compiler/implementation/ssa/codegen.dart
@@ -1796,7 +1796,8 @@
List<js.Expression> arguments = visitArguments(node.inputs, start: 0);
// TODO(floitsch): jsClassReference is an Access. We shouldn't treat it
// as if it was a string.
- push(new js.New(new js.VariableUse(jsClassReference), arguments), node);
+ js.Expression constructor = new js.VariableUse(jsClassReference);
+ push(new js.New(constructor, arguments), node);
registerForeignTypes(node);
if (node.instantiatedTypes == null) {
return;
@@ -1820,6 +1821,15 @@
FunctionConstant function = constant;
world.registerStaticUse(function.element);
}
+ if (constant.isType()) {
+ // If the type is a web component, we need to ensure the constructors are
+ // available to 'upgrade' the native object.
+ TypeConstant type = constant;
+ Element element = type.representedType.element;
+ if (element != null && element.isClass()) {
+ backend.registerEscapingConstructorsOfClass(element, world);
+ }
+ }
push(backend.emitter.constantReference(constant));
}
diff --git a/sdk/lib/_internal/compiler/implementation/ssa/nodes.dart b/sdk/lib/_internal/compiler/implementation/ssa/nodes.dart
index c3dc5a6..af8648d 100644
--- a/sdk/lib/_internal/compiler/implementation/ssa/nodes.dart
+++ b/sdk/lib/_internal/compiler/implementation/ssa/nodes.dart
@@ -1454,6 +1454,9 @@
}
class HInvokeConstructorBody extends HInvokeStatic {
+ // The 'inputs' are
+ // [receiver, arg1, ..., argN] or
+ // [interceptor, receiver, arg1, ... argN].
HInvokeConstructorBody(element, inputs)
: super(element, inputs, HType.UNKNOWN);
diff --git a/sdk/lib/_internal/compiler/implementation/typechecker.dart b/sdk/lib/_internal/compiler/implementation/typechecker.dart
index 2b2a399..2cc56ef 100644
--- a/sdk/lib/_internal/compiler/implementation/typechecker.dart
+++ b/sdk/lib/_internal/compiler/implementation/typechecker.dart
@@ -396,7 +396,23 @@
if (type.treatAsDynamic) {
return const DynamicAccess();
}
- Member member = type.lookupMember(name,
+ DartType originalType = type;
+ while (identical(type.kind, TypeKind.TYPE_VARIABLE)) {
+ TypeVariableType variable = type;
+ type = variable.element.bound;
+ if (type == originalType) {
+ type = compiler.objectClass.rawType;
+ }
+ }
+ if (type.kind == TypeKind.FUNCTION || type.kind == TypeKind.TYPEDEF) {
+ // TODO(karlklose): handle calling `call` on the function type. Do we have
+ // to type-check the arguments against the function type.
+ type = compiler.functionClass.rawType;
+ }
+ assert(invariant(node, type.kind == TypeKind.INTERFACE,
+ message: "unexpected type kind ${type.kind}."));
+ InterfaceType interface = type;
+ Member member = interface.lookupMember(name,
isSetter: identical(memberKind, MemberKind.SETTER));
if (member != null) {
checkPrivateAccess(node, member.element, name);
@@ -555,21 +571,6 @@
return const DynamicAccess();
}
TypeKind receiverKind = receiverType.kind;
- if (identical(receiverKind, TypeKind.TYPEDEF)) {
- // TODO(johnniwinther): handle typedefs.
- return const DynamicAccess();
- }
- if (identical(receiverKind, TypeKind.FUNCTION)) {
- // TODO(johnniwinther): handle functions.
- return const DynamicAccess();
- }
- if (identical(receiverKind, TypeKind.TYPE_VARIABLE)) {
- // TODO(johnniwinther): handle type variables.
- return const DynamicAccess();
- }
- assert(invariant(node.receiver,
- identical(receiverKind, TypeKind.INTERFACE),
- message: "interface type expected, got ${receiverKind}"));
return lookupMember(node, receiverType, name, memberKind);
} else {
return computeResolvedAccess(node, name, element, memberKind);
@@ -715,8 +716,10 @@
identical(name, '[]'),
message: 'Unexpected operator $name'));
- ElementAccess access = lookupMember(node, receiverType,
- operatorName, MemberKind.OPERATOR);
+ // TODO(karlklose): handle `void` in expression context by calling
+ // [analyzeNonVoid] instead of [analyze].
+ ElementAccess access = receiverType.isVoid ? const DynamicAccess()
+ : lookupMember(node, receiverType, operatorName, MemberKind.OPERATOR);
LinkBuilder<DartType> argumentTypesBuilder = new LinkBuilder<DartType>();
DartType resultType =
analyzeInvocation(node, access, argumentTypesBuilder);
diff --git a/sdk/lib/_internal/compiler/implementation/warnings.dart b/sdk/lib/_internal/compiler/implementation/warnings.dart
index 3c3729e..554a3bc 100644
--- a/sdk/lib/_internal/compiler/implementation/warnings.dart
+++ b/sdk/lib/_internal/compiler/implementation/warnings.dart
@@ -214,7 +214,7 @@
import 'dart:async'; // This imports a class Future.
import 'future.dart';
-void main() {}""",
+void main() => new Future();""",
'future.dart':
"""
@@ -228,7 +228,7 @@
import 'future.dart';
import 'dart:async'; // This imports a class Future.
-void main() {}""",
+void main() => new Future();""",
'future.dart':
"""
@@ -242,7 +242,7 @@
import 'export.dart';
import 'dart:async'; // This imports a class Future.
-void main() {}""",
+void main() => new Future();""",
'future.dart':
"""
@@ -269,7 +269,7 @@
// This hides the implicit import of class Type from dart:core.
import 'type.dart';
-void main() {}""",
+void main() => new Type();""",
'type.dart':
"""
@@ -278,7 +278,22 @@
class Type {}"""}]);
static const MessageKind DUPLICATE_EXPORT = const MessageKind(
- "Error: Duplicate export of '#{name}'.");
+ "Error: Duplicate export of '#{name}'.",
+ howToFix: "Trying adding 'hide #{name}' to one of the exports.",
+ examples: const [const {
+'main.dart': """
+export 'decl1.dart';
+export 'decl2.dart';
+
+main() {}""",
+'decl1.dart': "class Class {}",
+'decl2.dart': "class Class {}"}]);
+
+ static const MessageKind DUPLICATE_EXPORT_CONT = const MessageKind(
+ "Info: This is another export of '#{name}'.");
+
+ static const MessageKind DUPLICATE_EXPORT_DECL = const MessageKind(
+ "Info: The exported '#{name}' from export #{uriString} is defined here.");
static const DualKind NOT_A_TYPE = const DualKind(
error: const MessageKind("Error: '#{node}' is not a type."),
@@ -674,11 +689,11 @@
examples: const ["""
class C extends Object with String {}
-main() => new C();
+main() => new C();
""", """
typedef C = Object with String;
-main() => new C();
+main() => new C();
"""]);
static const MessageKind DUPLICATE_EXTENDS_IMPLEMENTS = const MessageKind(
@@ -894,6 +909,13 @@
const c; // This constant variable must be initialized.
}"""]);
+ static const MessageKind FINAL_WITHOUT_INITIALIZER = const MessageKind(
+ "Error: A final variable must be initialized.",
+ howToFix: "Try adding an initializer or "
+ "removing the 'final' modifier.",
+ examples: const [
+ "class C { static final field; } main() => C.field;"]);
+
static const MessageKind MEMBER_USES_CLASS_NAME = const MessageKind(
"Error: Member variable can't have the same name as the class it is "
"declared in.",
@@ -965,13 +987,13 @@
"operator.");
static const MessageKind AMBIGUOUS_REEXPORT = const MessageKind(
- "Info: '#{element}' is (re)exported by multiple libraries.");
+ "Info: '#{name}' is (re)exported by multiple libraries.");
static const MessageKind AMBIGUOUS_LOCATION = const MessageKind(
- "Info: '#{element}' is defined here.");
+ "Info: '#{name}' is defined here.");
static const MessageKind IMPORTED_HERE = const MessageKind(
- "Info: '#{element}' is imported here.");
+ "Info: '#{name}' is imported here.");
static const MessageKind OVERRIDE_EQUALS_NOT_HASH_CODE = const MessageKind(
"Hint: The class '#{class}' overrides 'operator==', "
diff --git a/sdk/lib/_internal/dartdoc/lib/dartdoc.dart b/sdk/lib/_internal/dartdoc/lib/dartdoc.dart
index 1f94af6..c4fa58f 100644
--- a/sdk/lib/_internal/dartdoc/lib/dartdoc.dart
+++ b/sdk/lib/_internal/dartdoc/lib/dartdoc.dart
@@ -80,15 +80,7 @@
if (outputDir.existsSync()) {
outputDir.deleteSync(recursive: true);
}
-
- try {
- // TODO(3914): Hack to avoid 'file already exists' exception thrown
- // due to invalid result from dir.existsSync() (probably due to race
- // conditions).
- outputDir.createSync();
- } on DirectoryException catch (e) {
- // Ignore.
- }
+ outputDir.createSync();
}
/**
@@ -359,7 +351,7 @@
[new md.CodeSyntax(r'\[:\s?((?:.|\n)*?)\s?:\]')];
Dartdoc() {
- tmpPath = new Directory('').createTempSync().path;
+ tmpPath = Directory.systemTemp.createTempSync('dartdoc_').path;
dartdocResolver = (String name) => resolveNameReference(name,
currentLibrary: _currentLibrary, currentType: _currentType,
currentMember: _currentMember);
diff --git a/sdk/lib/_internal/dartdoc/test/export_map_test.dart b/sdk/lib/_internal/dartdoc/test/export_map_test.dart
index ed5e392..4d43bd4 100644
--- a/sdk/lib/_internal/dartdoc/test/export_map_test.dart
+++ b/sdk/lib/_internal/dartdoc/test/export_map_test.dart
@@ -389,7 +389,7 @@
String libPath(String name) => pathos.normalize(pathos.join(tempDir, name));
void createTempDir() {
- tempDir = new Directory('').createTempSync().path;
+ tempDir = Directory.systemTemp.createTempSync('dartdoc_').path;
new Directory(pathos.join(tempDir, 'packages')).createSync();
}
diff --git a/sdk/lib/_internal/lib/interceptors.dart b/sdk/lib/_internal/lib/interceptors.dart
index 9dff6fb..78b591d 100644
--- a/sdk/lib/_internal/lib/interceptors.dart
+++ b/sdk/lib/_internal/lib/interceptors.dart
@@ -151,9 +151,10 @@
/**
- * Data structure used to map a [Type] to the [Interceptor] for that type. It
- * is JavaScript array of 2N entries of adjacent slots containing a [Type]
- * followed by an [Interceptor] class for the type.
+ * Data structure used to map a [Type] to the [Interceptor] and constructors for
+ * that type. It is JavaScript array of 3N entries of adjacent slots containing
+ * a [Type], followed by an [Interceptor] class for the type, followed by a
+ * JavaScript object map for the constructors.
*
* The value of this variable is set by the compiler and contains only types
* that are user extensions of native classes where the type occurs as a
@@ -162,18 +163,40 @@
// TODO(sra): Mark this as initialized to a constant with unknown value.
var mapTypeToInterceptor;
-findInterceptorConstructorForType(Type type) {
+int findIndexForWebComponentType(Type type) {
JS_EFFECT((_){ mapTypeToInterceptor = _; });
if (mapTypeToInterceptor == null) return null;
List map = JS('JSFixedArray', '#', mapTypeToInterceptor);
- for (int i = 0; i + 1 < map.length; i += 2) {
+ for (int i = 0; i + 1 < map.length; i += 3) {
if (type == map[i]) {
- return map[i + 1];
+ return i;
}
}
return null;
}
+findInterceptorConstructorForType(Type type) {
+ var index = findIndexForWebComponentType(type);
+ if (index == null) return null;
+ List map = JS('JSFixedArray', '#', mapTypeToInterceptor);
+ return mapTypeToInterceptor[index + 1];
+}
+
+/**
+ * Returns a JavaScript function that runs the constructor on its argument, or
+ * `null` if there is no such constructor.
+ *
+ * The returned function takes one argument, the web component object.
+ */
+findConstructorForWebComponentType(Type type, String name) {
+ var index = findIndexForWebComponentType(type);
+ if (index == null) return null;
+ List map = JS('JSFixedArray', '#', mapTypeToInterceptor);
+ var constructorMap = mapTypeToInterceptor[index + 2];
+ var constructorFn = JS('', '#[#]', constructorMap, name);
+ return constructorFn;
+}
+
findInterceptorForType(Type type) {
var constructor = findInterceptorConstructorForType(type);
if (constructor == null) return null;
diff --git a/sdk/lib/_internal/lib/io_patch.dart b/sdk/lib/_internal/lib/io_patch.dart
index dd4444a..0acb7d4 100644
--- a/sdk/lib/_internal/lib/io_patch.dart
+++ b/sdk/lib/_internal/lib/io_patch.dart
@@ -9,9 +9,12 @@
patch static _setCurrent(path) {
throw new UnsupportedError("Directory_SetCurrent");
}
- patch static _createTemp(String template, bool system) {
+ patch static _createTemp(String path) {
throw new UnsupportedError("Directory._createTemp");
}
+ patch static String _systemTemp() {
+ throw new UnsupportedError("Directory._systemTemp");
+ }
patch static int _exists(String path) {
throw new UnsupportedError("Directory._exists");
}
diff --git a/sdk/lib/_internal/lib/js_array.dart b/sdk/lib/_internal/lib/js_array.dart
index 5718c5d..b6ec0cb 100644
--- a/sdk/lib/_internal/lib/js_array.dart
+++ b/sdk/lib/_internal/lib/js_array.dart
@@ -243,6 +243,10 @@
IterableMixinWorkaround.sortList(this, compare);
}
+ void shuffle() {
+ IterableMixinWorkaround.shuffleList(this);
+ }
+
int indexOf(Object element, [int start = 0]) {
return IterableMixinWorkaround.indexOfList(this, element, start);
}
diff --git a/sdk/lib/_internal/lib/js_mirrors.dart b/sdk/lib/_internal/lib/js_mirrors.dart
index 2887c43..4d0fe51 100644
--- a/sdk/lib/_internal/lib/js_mirrors.dart
+++ b/sdk/lib/_internal/lib/js_mirrors.dart
@@ -781,18 +781,9 @@
}
int get hashCode {
- // If the reflectee is a built-in type, use the base-level hashCode to
- // preserve the illusion that, e.g. doubles, with the same value are
- // identical. Otherwise, use the primitive identity hash to maintain
- // correctness even if a user-defined hashCode returns different values for
- // successive invocations.
- var h = ((JS('bool', 'typeof # != "object"', reflectee)) ||
- (reflectee == null))
- ? reflectee.hashCode
- : Primitives.objectHashCode(reflectee);
// Avoid hash collisions with the reflectee. This constant is in Smi range
// and happens to be the inner padding from RFC 2104.
- return h ^ 0x36363636;
+ return identityHashCode(reflectee) ^ 0x36363636;
}
String toString() => 'InstanceMirror on ${Error.safeToString(reflectee)}';
diff --git a/sdk/lib/_internal/lib/math_patch.dart b/sdk/lib/_internal/lib/math_patch.dart
index 3bccb2c..7def542 100644
--- a/sdk/lib/_internal/lib/math_patch.dart
+++ b/sdk/lib/_internal/lib/math_patch.dart
@@ -4,6 +4,7 @@
// Patch file for dart:math library.
import 'dart:_foreign_helper' show JS;
+import 'dart:_js_helper' show checkNum;
patch double sqrt(num x)
=> JS('double', r'Math.sqrt(#)', checkNum(x));
diff --git a/sdk/lib/_internal/lib/mirrors_patch.dart b/sdk/lib/_internal/lib/mirrors_patch.dart
index 4700984..ad05409 100644
--- a/sdk/lib/_internal/lib/mirrors_patch.dart
+++ b/sdk/lib/_internal/lib/mirrors_patch.dart
@@ -19,5 +19,8 @@
patch InstanceMirror reflect(Object reflectee) => js.reflect(reflectee);
patch ClassMirror reflectClass(Type key) {
+ if (key is! Type || key == dynamic) {
+ throw new ArgumentError('$key does not denote a class');
+ }
return js.reflectType(key).originalDeclaration;
}
diff --git a/sdk/lib/_internal/pub/lib/src/barback.dart b/sdk/lib/_internal/pub/lib/src/barback.dart
index 803ec64..70b36b5 100644
--- a/sdk/lib/_internal/pub/lib/src/barback.dart
+++ b/sdk/lib/_internal/pub/lib/src/barback.dart
@@ -7,7 +7,10 @@
import 'dart:async';
import 'package:barback/barback.dart';
+import 'package:path/path.dart' as path;
+import 'barback/dart_forwarding_transformer.dart';
+import 'barback/dart2js_transformer.dart';
import 'barback/load_all_transformers.dart';
import 'barback/pub_package_provider.dart';
import 'barback/server.dart';
@@ -54,6 +57,14 @@
Future<BarbackServer> createServer(String host, int port, PackageGraph graph) {
var provider = new PubPackageProvider(graph);
var barback = new Barback(provider);
+
+ // TODO(rnystrom): Add dart2dart transformer here and some way to configure
+ // them.
+ var builtInTransformers = [
+ new Dart2JSTransformer(graph),
+ new DartForwardingTransformer()
+ ];
+
return BarbackServer.bind(host, port, barback, graph.entrypoint.root.name)
.then((server) {
watchSources(graph, barback);
@@ -75,7 +86,7 @@
})
];
- loadAllTransformers(server, graph).then((_) {
+ loadAllTransformers(server, graph, builtInTransformers).then((_) {
if (!completer.isCompleted) completer.complete(server);
}).catchError((error) {
if (!completer.isCompleted) completer.completeError(error);
@@ -141,3 +152,38 @@
return new Uri(scheme: 'package', path: id.path.replaceFirst('lib/', ''));
}
+
+/// Converts [uri] into an [AssetId] if it has a path containing "packages" or
+/// "assets".
+///
+/// If the URI doesn't contain one of those special directories, returns null.
+/// If it does contain a special directory, but lacks a following package name,
+/// throws a [FormatException].
+AssetId specialUrlToId(Uri url) {
+ var parts = path.url.split(url.path);
+
+ for (var pair in [["packages", "lib"], ["assets", "asset"]]) {
+ var partName = pair.first;
+ var dirName = pair.last;
+
+ // Find the package name and the relative path in the package.
+ var index = parts.indexOf(partName);
+ if (index == -1) continue;
+
+ // If we got here, the path *did* contain the special directory, which
+ // means we should not interpret it as a regular path. If it's missing the
+ // package name after the special directory, it's invalid.
+ if (index + 1 >= parts.length) {
+ throw new FormatException(
+ 'Invalid package path "${path.url.joinAll(parts)}". '
+ 'Expected package name after "$partName".');
+ }
+
+ var package = parts[index + 1];
+ var assetPath = path.url.join(dirName,
+ path.url.joinAll(parts.skip(index + 2)));
+ return new AssetId(package, assetPath);
+ }
+
+ return null;
+}
diff --git a/sdk/lib/_internal/pub/lib/src/barback/dart2js_transformer.dart b/sdk/lib/_internal/pub/lib/src/barback/dart2js_transformer.dart
new file mode 100644
index 0000000..9405f43
--- /dev/null
+++ b/sdk/lib/_internal/pub/lib/src/barback/dart2js_transformer.dart
@@ -0,0 +1,226 @@
+// 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.dart2js_transformer;
+
+import 'dart:async';
+import 'dart:io';
+
+import 'package:analyzer_experimental/analyzer.dart';
+import 'package:barback/barback.dart';
+import 'package:path/path.dart' as path;
+
+import '../../../../compiler/compiler.dart' as compiler;
+import '../../../../compiler/implementation/dart2js.dart'
+ show AbortLeg;
+import '../../../../compiler/implementation/source_file.dart';
+import '../barback.dart';
+import '../dart.dart' as dart;
+import '../io.dart';
+import '../package.dart';
+import '../package_graph.dart';
+
+/// A [Transformer] that uses dart2js's library API to transform Dart
+/// entrypoints in "web" to JavaScript.
+class Dart2JSTransformer extends Transformer {
+ final PackageGraph _graph;
+
+ Dart2JSTransformer(this._graph);
+
+ /// Only ".dart" files within "web/" are processed.
+ Future<bool> isPrimary(Asset asset) {
+ return new Future.value(
+ asset.id.extension == ".dart" &&
+ asset.id.path.startsWith("web/"));
+ }
+
+ Future apply(Transform transform) {
+ var stopwatch = new Stopwatch();
+ stopwatch.start();
+
+ return transform.primaryInput.readAsString().then((code) {
+ try {
+ if (!dart.isEntrypoint(parseCompilationUnit(code))) return;
+ } on AnalyzerErrorGroup catch (e) {
+ transform.logger.error(e.message);
+ return;
+ }
+
+ var provider = new _BarbackInputProvider(_graph, transform);
+
+ // Create a "path" to the entrypoint script. The entrypoint may not
+ // actually be on disk, but this gives dart2js a root to resolve
+ // relative paths against.
+ var id = transform.primaryInput.id;
+ var entrypoint = path.join(_graph.packages[id.package].dir, id.path);
+ var packageRoot = path.join(_graph.entrypoint.root.dir, "packages");
+
+ // TODO(rnystrom): Should have more sophisticated error-handling here.
+ // Need to report compile errors to the user in an easily visible way.
+ // Need to make sure paths in errors are mapped to the original source
+ // path so they can understand them.
+ return dart.compile(entrypoint,
+ packageRoot: packageRoot,
+ inputProvider: provider.readStringFromUri,
+ diagnosticHandler: provider.handleDiagnostic).then((js) {
+ var id = transform.primaryInput.id.changeExtension(".dart.js");
+ transform.addOutput(new Asset.fromString(id, js));
+
+ stopwatch.stop();
+ transform.logger.info("Generated $id (${js.length} characters) in "
+ "${stopwatch.elapsed}");
+ });
+ });
+ }
+}
+
+/// Defines methods implementig [CompilerInputProvider] and [DiagnosticHandler]
+/// for dart2js to use to load files from Barback and report errors.
+///
+/// Note that most of the implementation of diagnostic handling here was
+/// copied from [FormattingDiagnosticHandler] in dart2js. The primary
+/// difference is that it uses barback's logging code and, more importantly, it
+/// handles missing source files more gracefully.
+class _BarbackInputProvider {
+ final PackageGraph _graph;
+ final Transform _transform;
+
+ /// The map of previously loaded files.
+ ///
+ /// Used to show where an error occurred in a source file.
+ final _sourceFiles = new Map<String, SourceFile>();
+
+ // TODO(rnystrom): Make these configurable.
+ /// Whether or not warnings should be logged.
+ var _showWarnings = true;
+
+ /// Whether or not hints should be logged.
+ var _showHints = true;
+
+ /// Whether or not verbose info messages should be logged.
+ var _verbose = false;
+
+ /// Whether an exception should be thrown on an error to stop compilation.
+ var _throwOnError = false;
+
+ /// This gets set after a fatal error is reported to quash any subsequent
+ /// errors.
+ var _isAborting = false;
+
+ compiler.Diagnostic _lastKind = null;
+
+ static final int _FATAL =
+ compiler.Diagnostic.CRASH.ordinal |
+ compiler.Diagnostic.ERROR.ordinal;
+ static final int _INFO =
+ compiler.Diagnostic.INFO.ordinal |
+ compiler.Diagnostic.VERBOSE_INFO.ordinal;
+
+ _BarbackInputProvider(this._graph, this._transform);
+
+ /// A [CompilerInputProvider] for dart2js.
+ Future<String> readStringFromUri(Uri resourceUri) {
+ // We only expect to get absolute "file:" URLs from dart2js.
+ assert(resourceUri.isAbsolute);
+ assert(resourceUri.scheme == "file");
+
+ var sourcePath = path.fromUri(resourceUri);
+ return _readResource(resourceUri).then((source) {
+ _sourceFiles[resourceUri.toString()] =
+ new SourceFile(path.relative(sourcePath), source);
+ return source;
+ });
+ }
+
+ /// A [DiagnosticHandler] for dart2js, loosely based on
+ /// [FormattingDiagnosticHandler].
+ void handleDiagnostic(Uri uri, int begin, int end,
+ String message, compiler.Diagnostic kind) {
+ // TODO(ahe): Remove this when source map is handled differently.
+ if (kind.name == "source map") return;
+
+ if (_isAborting) return;
+ _isAborting = (kind == compiler.Diagnostic.CRASH);
+
+ var isInfo = (kind.ordinal & _INFO) != 0;
+ if (isInfo && uri == null && kind != compiler.Diagnostic.INFO) {
+ if (!_verbose && kind == compiler.Diagnostic.VERBOSE_INFO) return;
+ _transform.logger.info(message);
+ return;
+ }
+
+ // [_lastKind] records the previous non-INFO kind we saw.
+ // This is used to suppress info about a warning when warnings are
+ // suppressed, and similar for hints.
+ if (kind != compiler.Diagnostic.INFO) _lastKind = kind;
+
+ var logFn;
+ if (kind == compiler.Diagnostic.ERROR) {
+ logFn = _transform.logger.error;
+ } else if (kind == compiler.Diagnostic.WARNING) {
+ if (!_showWarnings) return;
+ logFn = _transform.logger.warning;
+ } else if (kind == compiler.Diagnostic.HINT) {
+ if (!_showHints) return;
+ logFn = _transform.logger.warning;
+ } else if (kind == compiler.Diagnostic.CRASH) {
+ logFn = _transform.logger.error;
+ } else if (kind == compiler.Diagnostic.INFO) {
+ if (_lastKind == compiler.Diagnostic.WARNING && !_showWarnings) return;
+ if (_lastKind == compiler.Diagnostic.HINT && !_showHints) return;
+ logFn = _transform.logger.info;
+ } else {
+ throw new Exception('Unknown kind: $kind (${kind.ordinal})');
+ }
+
+ var fatal = (kind.ordinal & _FATAL) != 0;
+ if (uri == null) {
+ assert(fatal);
+ logFn(message);
+ } else {
+ SourceFile file = _sourceFiles[uri.toString()];
+ if (file == null) {
+ // We got a message before loading the file, so just report the message
+ // itself.
+ logFn('$uri: $message');
+ } else {
+ logFn(file.getLocationMessage(message, begin, end, true, (i) => i));
+ }
+ }
+
+ if (fatal && _throwOnError) {
+ _isAborting = true;
+ throw new AbortLeg(message);
+ }
+ }
+
+ Future<String> _readResource(Uri url) {
+ // See if the path is within a package. If so, use Barback so we can use
+ // generated Dart assets.
+ var id = _sourceUrlToId(url);
+ if (id != null) return _transform.readInputAsString(id);
+
+ // If we get here, the path doesn't appear to be in a package, so we'll
+ // skip Barback and just hit the file system. This will occur at the very
+ // least for dart2js's implementations of the core libraries.
+ var sourcePath = path.fromUri(url);
+ return new File(sourcePath).readAsString();
+ }
+
+ AssetId _sourceUrlToId(Uri url) {
+ // See if it's a special path with "packages" or "assets" in it.
+ var id = specialUrlToId(url);
+ if (id != null) return id;
+
+ // See if it's a path within the root package.
+ var rootDir = _graph.entrypoint.root.dir;
+ var sourcePath = path.fromUri(url);
+ if (isBeneath(sourcePath, rootDir)) {
+ var relative = path.relative(sourcePath, from: rootDir);
+ return new AssetId(_graph.entrypoint.root.name, relative);
+ }
+
+ return null;
+ }
+}
diff --git a/sdk/lib/_internal/pub/lib/src/barback/dart_forwarding_transformer.dart b/sdk/lib/_internal/pub/lib/src/barback/dart_forwarding_transformer.dart
new file mode 100644
index 0000000..8c25a38
--- /dev/null
+++ b/sdk/lib/_internal/pub/lib/src/barback/dart_forwarding_transformer.dart
@@ -0,0 +1,26 @@
+// 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.dart_forwarding_transformer;
+
+import 'dart:async';
+
+import 'package:barback/barback.dart';
+
+import '../utils.dart';
+
+/// A single transformer that just forwards any ".dart" file as an output.
+///
+/// Since the [Dart2JSTransformer] consumes its inputs, this is used in
+/// parallel to make sure the original Dart file is still available for use by
+/// Dartium.
+class DartForwardingTransformer extends Transformer {
+ String get allowedExtensions => ".dart";
+
+ Future apply(Transform transform) {
+ return newFuture(() {
+ transform.addOutput(transform.primaryInput);
+ });
+ }
+}
diff --git a/sdk/lib/_internal/pub/lib/src/barback/load_all_transformers.dart b/sdk/lib/_internal/pub/lib/src/barback/load_all_transformers.dart
index 3efce84..a03ce3a 100644
--- a/sdk/lib/_internal/pub/lib/src/barback/load_all_transformers.dart
+++ b/sdk/lib/_internal/pub/lib/src/barback/load_all_transformers.dart
@@ -19,7 +19,11 @@
///
/// This uses [server] to serve the Dart files from which transformers are
/// loaded, then adds the transformers to `server.barback`.
-Future loadAllTransformers(BarbackServer server, PackageGraph graph) {
+///
+/// Any [builtInTransformers] that are provided will automatically be added to
+/// the end of every package's cascade.
+Future loadAllTransformers(BarbackServer server, PackageGraph graph,
+ [Iterable<Transformer> builtInTransformers]) {
// In order to determine in what order we should load transformers, we need to
// know which transformers depend on which others. This is different than
// normal package dependencies. Let's begin with some terminology:
@@ -109,7 +113,12 @@
for (var package in graph.packages.values) {
var phases = package.pubspec.transformers.map((phase) {
return unionAll(phase.map((id) => loader.transformersFor(id)));
- });
+ }).toList();
+
+ if (builtInTransformers != null && builtInTransformers.isNotEmpty) {
+ phases.add(builtInTransformers);
+ }
+
server.barback.updateTransformers(package.name, phases);
}
});
diff --git a/sdk/lib/_internal/pub/lib/src/barback/server.dart b/sdk/lib/_internal/pub/lib/src/barback/server.dart
index 3b8c154..36faf4a 100644
--- a/sdk/lib/_internal/pub/lib/src/barback/server.dart
+++ b/sdk/lib/_internal/pub/lib/src/barback/server.dart
@@ -11,6 +11,7 @@
import 'package:path/path.dart' as path;
import 'package:stack_trace/stack_trace.dart';
+import '../barback.dart';
import '../log.dart' as log;
import '../utils.dart';
@@ -74,9 +75,13 @@
return;
}
- var id = _getIdFromUri(request.uri);
- if (id == null) {
- _notFound(request, "Path ${request.uri.path} is not valid.");
+ var id;
+ try {
+ id = _uriToId(_rootPackage, request.uri);
+ } on FormatException catch (ex) {
+ // 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.
+ _notFound(request, ex.message);
return;
}
@@ -130,6 +135,22 @@
});
}
+ /// Converts a [url] served by pub serve into an [AssetId] that can be
+ /// requested from barback.
+ AssetId _uriToId(String rootPackage, Uri url) {
+ var id = specialUrlToId(url);
+ if (id != null) return id;
+
+ // Otherwise, it's a path in current package's web directory.
+ var parts = path.url.split(url.path);
+
+ // Strip the leading "/" from the URL.
+ parts = parts.skip(1);
+
+ var relativePath = path.url.join("web", path.url.joinAll(parts));
+ return new AssetId(rootPackage, relativePath);
+ }
+
/// Responds to [request] with a 405 response and closes it.
void _methodNotAllowed(HttpRequest request) {
_logRequest(request, "405 Method Not Allowed");
@@ -150,53 +171,6 @@
request.response.close();
}
- /// Converts a request [uri] into an [AssetId] that can be requested from
- /// barback.
- 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(_rootPackage,
- path.url.join("web", path.url.joinAll(parts)));
- }
-
/// Log [message] at [log.Level.FINE] with metadata about [request].
void _logRequest(HttpRequest request, String message) =>
log.fine("BarbackServer ${request.method} ${request.uri}\n$message");
diff --git a/sdk/lib/_internal/pub/lib/src/barback/watch_sources.dart b/sdk/lib/_internal/pub/lib/src/barback/watch_sources.dart
index 89f474c..bc1c7ec 100644
--- a/sdk/lib/_internal/pub/lib/src/barback/watch_sources.dart
+++ b/sdk/lib/_internal/pub/lib/src/barback/watch_sources.dart
@@ -26,6 +26,11 @@
// TODO(nweiz): close these watchers when [barback] is closed.
var watcher = new DirectoryWatcher(subdirectory);
watcher.events.listen((event) {
+ // Don't watch files symlinked into these directories.
+ // TODO(rnystrom): If pub gets rid of symlinks, remove this.
+ var parts = path.split(event.path);
+ if (parts.contains("packages") || parts.contains("assets")) return;
+
var id = new AssetId(package.name,
path.relative(event.path, from: package.dir));
if (event.type == ChangeType.REMOVE) {
diff --git a/sdk/lib/_internal/pub/lib/src/dart.dart b/sdk/lib/_internal/pub/lib/src/dart.dart
index f6d8b11..4c746d1 100644
--- a/sdk/lib/_internal/pub/lib/src/dart.dart
+++ b/sdk/lib/_internal/pub/lib/src/dart.dart
@@ -26,31 +26,48 @@
///
/// By default, the package root is assumed to be adjacent to [entrypoint], but
/// if [packageRoot] is passed that will be used instead.
+///
+/// If [inputProvider] and [diagnosticHandler] are omitted, uses a default
+/// [compiler.CompilerInputProvider] that loads directly from the filesystem.
+/// If either is provided, both must be.
Future<String> compile(String entrypoint, {String packageRoot,
- bool toDart: false}) {
+ bool toDart: false, compiler.CompilerInputProvider inputProvider,
+ compiler.DiagnosticHandler diagnosticHandler}) {
return new Future.sync(() {
- var provider = new SourceFileProvider();
var options = <String>['--categories=Client,Server', '--minify'];
if (toDart) options.add('--output-type=dart');
if (packageRoot == null) {
packageRoot = path.join(path.dirname(entrypoint), 'packages');
}
+ // Must either pass both of these or neither.
+ if ((inputProvider == null) != (diagnosticHandler == null)) {
+ throw new ArgumentError("If either inputProvider or diagnosticHandler "
+ "is passed, then both must be.");
+ }
+
+ if (inputProvider == null) {
+ var provider = new SourceFileProvider();
+ inputProvider = provider.readStringFromUri;
+ diagnosticHandler = new FormattingDiagnosticHandler(provider)
+ .diagnosticHandler;
+ }
+
return compiler.compile(
path.toUri(entrypoint),
path.toUri(appendSlash(_libPath)),
path.toUri(appendSlash(packageRoot)),
- provider.readStringFromUri,
- new FormattingDiagnosticHandler(provider).diagnosticHandler,
- options);
+ inputProvider, diagnosticHandler, options);
}).then((result) {
if (result != null) return result;
throw new ApplicationException('Failed to compile "$entrypoint".');
});
}
-/// Returns the path to the library directory. This corresponds to the "sdk"
-/// directory in the repo and to the root of the compiled SDK.
+/// Returns the path to the directory containing the Dart core libraries.
+///
+/// This corresponds to the "sdk" directory in the repo and to the root of the
+/// compiled SDK.
String get _libPath {
if (runningFromSdk) return sdk.rootDirectory;
return path.join(repoRoot, 'sdk');
diff --git a/sdk/lib/_internal/pub/lib/src/io.dart b/sdk/lib/_internal/pub/lib/src/io.dart
index af8168e..d27fe13 100644
--- a/sdk/lib/_internal/pub/lib/src/io.dart
+++ b/sdk/lib/_internal/pub/lib/src/io.dart
@@ -228,23 +228,24 @@
return dirPath;
}
-/// Creates a temp directory whose name will be based on [dir] with a unique
-/// suffix appended to it. If [dir] is not provided, a temp directory will be
-/// created in a platform-dependent temporary location. Returns the path of the
-/// created directory.
+/// Creates a temp directory in [dir], whose name will be [prefix] with
+/// characters appended to it to make a unique name.
+/// Returns the path of the created directory.
String createTempDir(String base, String prefix) {
var tempDir = new Directory(base).createTempSync(prefix);
log.io("Created temp directory ${tempDir.path}");
return tempDir.path;
}
+/// Creates a temp directory in the system temp directory, whose name will be
+/// 'pub_' with characters appended to it to make a unique name.
+/// Returns the path of the created directory.
String createSystemTempDir() {
- var tempDir = Directory.createSystemTempSync('pub_');
+ var tempDir = Directory.systemTemp.createTempSync('pub_');
log.io("Created temp directory ${tempDir.path}");
return tempDir.path;
}
-
/// Lists the contents of [dir]. If [recursive] is `true`, lists subdirectory
/// contents (defaults to `false`). If [includeHidden] is `true`, includes files
/// and directories beginning with `.` (defaults to `false`).
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
index 529facb..6d46bac 100644
--- 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
@@ -15,19 +15,19 @@
d.appPubspec(),
d.dir("web", [
d.file("index.html", "<body>"),
- d.file("file.dart", "void main() => print('hello');"),
+ d.file("file.dart", "main() => print('hello');"),
d.dir("sub", [
d.file("file.html", "<body>in subdir</body>"),
- d.file("lib.dart", "void foo() => 'foo';"),
+ d.file("lib.dart", "main() => 'foo';"),
])
])
]).create();
startPubServe();
requestShouldSucceed("index.html", "<body>");
- requestShouldSucceed("file.dart", "void main() => print('hello');");
+ requestShouldSucceed("file.dart", "main() => print('hello');");
requestShouldSucceed("sub/file.html", "<body>in subdir</body>");
- requestShouldSucceed("sub/lib.dart", "void foo() => 'foo';");
+ requestShouldSucceed("sub/lib.dart", "main() => 'foo';");
endPubServe();
});
}
diff --git a/sdk/lib/_internal/pub/test/serve/utils.dart b/sdk/lib/_internal/pub/test/serve/utils.dart
index 6c5f1ec..46d2a14 100644
--- a/sdk/lib/_internal/pub/test/serve/utils.dart
+++ b/sdk/lib/_internal/pub/test/serve/utils.dart
@@ -120,11 +120,13 @@
}
/// Schedules an HTTP request to the running pub server with [urlPath] and
-/// verifies that it responds with [expected].
-void requestShouldSucceed(String urlPath, String expected) {
+/// verifies that it responds with a body that matches [expectation].
+///
+/// [expectation] may either be a [Matcher] or a string to match an exact body.
+void requestShouldSucceed(String urlPath, expectation) {
schedule(() {
return http.get("http://127.0.0.1:$_port/$urlPath").then((response) {
- expect(response.body, equals(expected));
+ expect(response.body, expectation);
});
}, "request $urlPath");
}
diff --git a/sdk/lib/_internal/pub/test/transformer/dart2js/allows_import_in_dart_code_test.dart b/sdk/lib/_internal/pub/test/transformer/dart2js/allows_import_in_dart_code_test.dart
new file mode 100644
index 0000000..441ef8b
--- /dev/null
+++ b/sdk/lib/_internal/pub/test/transformer/dart2js/allows_import_in_dart_code_test.dart
@@ -0,0 +1,53 @@
+// 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 'package:scheduled_test/scheduled_test.dart';
+
+import '../../descriptor.dart' as d;
+import '../../test_pub.dart';
+import '../../serve/utils.dart';
+
+main() {
+ initConfig();
+ integration("handles imports in the Dart code", () {
+ d.dir("foo", [
+ d.libPubspec("foo", "0.0.1"),
+ d.dir("lib", [
+ d.file("foo.dart", """
+library foo;
+foo() => 'footext';
+""")
+ ])
+ ]).create();
+
+ d.dir(appPath, [
+ d.appPubspec({
+ "foo": {"path": "../foo"}
+ }),
+ d.dir("lib", [
+ d.file("lib.dart", """
+library lib;
+lib() => 'libtext';
+""")
+ ]),
+ d.dir("web", [
+ d.file("main.dart", """
+import 'package:foo/foo.dart';
+import 'package:myapp/lib.dart';
+void main() {
+ print(foo());
+ print(lib());
+}
+""")
+ ])
+ ]).create();
+
+ startPubServe(shouldInstallFirst: true);
+ requestShouldSucceed("main.dart.js", contains("footext"));
+ requestShouldSucceed("main.dart.js", contains("libtext"));
+ endPubServe();
+ });
+}
diff --git a/sdk/lib/_internal/pub/test/transformer/dart2js/compiles_generated_dart_file_test.dart b/sdk/lib/_internal/pub/test/transformer/dart2js/compiles_generated_dart_file_test.dart
new file mode 100644
index 0000000..399c2ce
--- /dev/null
+++ b/sdk/lib/_internal/pub/test/transformer/dart2js/compiles_generated_dart_file_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 'package:scheduled_test/scheduled_test.dart';
+
+import '../../descriptor.dart' as d;
+import '../../test_pub.dart';
+import '../../serve/utils.dart';
+
+main() {
+ initConfig();
+ integration("compiles a generated Dart file to JS", () {
+ d.dir(appPath, [
+ d.pubspec({
+ "name": "myapp",
+ "version": "0.0.1",
+ "transformers": ["myapp/transformer"]
+ }),
+ d.dir("lib", [
+ d.file("transformer.dart", dartTransformer("munge"))
+ ]),
+ d.dir("web", [
+ d.file("main.dart", """
+const TOKEN = "before";
+void main() => print(TOKEN);
+""")
+ ])
+ ]).create();
+
+ createLockFile('myapp', pkg: ['barback']);
+
+ startPubServe();
+ requestShouldSucceed("main.dart.js", contains("(before, munge)"));
+ endPubServe();
+ });
+}
diff --git a/sdk/lib/_internal/pub/test/transformer/dart2js/compiles_generated_file_from_dependency_test.dart b/sdk/lib/_internal/pub/test/transformer/dart2js/compiles_generated_file_from_dependency_test.dart
new file mode 100644
index 0000000..45dc8a3
--- /dev/null
+++ b/sdk/lib/_internal/pub/test/transformer/dart2js/compiles_generated_file_from_dependency_test.dart
@@ -0,0 +1,53 @@
+// 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 'package:scheduled_test/scheduled_test.dart';
+
+import '../../descriptor.dart' as d;
+import '../../test_pub.dart';
+import '../../serve/utils.dart';
+
+main() {
+ initConfig();
+ integration("compiles a Dart file that imports a generated file in another "
+ "package to JS", () {
+ d.dir("foo", [
+ d.pubspec({
+ "name": "foo",
+ "version": "0.0.1",
+ "transformers": ["foo/transformer"]
+ }),
+ d.dir("lib", [
+ d.file("foo.dart", """
+library foo;
+const TOKEN = "before";
+foo() => TOKEN;
+"""),
+ d.file("transformer.dart", dartTransformer("munge"))
+ ])
+ ]).create();
+
+ d.dir(appPath, [
+ d.appPubspec({
+ "foo": {
+ "path": "../foo"
+ }
+ }),
+ d.dir("web", [
+ d.file("main.dart", """
+import "package:foo/foo.dart";
+main() => print(foo());
+""")
+ ])
+ ]).create();
+
+ createLockFile("myapp", sandbox: ["foo"], pkg: ["barback"]);
+
+ startPubServe();
+ requestShouldSucceed("main.dart.js", contains("(before, munge)"));
+ endPubServe();
+ });
+}
diff --git a/sdk/lib/_internal/pub/test/transformer/dart2js/compiles_imported_generated_file_test.dart b/sdk/lib/_internal/pub/test/transformer/dart2js/compiles_imported_generated_file_test.dart
new file mode 100644
index 0000000..f5fb55d
--- /dev/null
+++ b/sdk/lib/_internal/pub/test/transformer/dart2js/compiles_imported_generated_file_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 'package:scheduled_test/scheduled_test.dart';
+
+import '../../descriptor.dart' as d;
+import '../../test_pub.dart';
+import '../../serve/utils.dart';
+
+main() {
+ initConfig();
+ integration("compiles a Dart file that imports a generated file to JS", () {
+ d.dir(appPath, [
+ d.pubspec({
+ "name": "myapp",
+ "version": "0.0.1",
+ "transformers": ["myapp/transformer"]
+ }),
+ d.dir("lib", [
+ d.file("transformer.dart", dartTransformer("munge"))
+ ]),
+ d.dir("web", [
+ d.file("main.dart", """
+import "other.dart";
+void main() => print(TOKEN);
+"""),
+d.file("other.dart", """
+library other;
+const TOKEN = "before";
+""")
+ ])
+ ]).create();
+
+ createLockFile('myapp', pkg: ['barback']);
+
+ startPubServe();
+ requestShouldSucceed("main.dart.js", contains("(before, munge)"));
+ endPubServe();
+ });
+}
diff --git a/sdk/lib/_internal/pub/test/transformer/dart2js/converts_entrypoint_in_web_test.dart b/sdk/lib/_internal/pub/test/transformer/dart2js/converts_entrypoint_in_web_test.dart
new file mode 100644
index 0000000..538930a
--- /dev/null
+++ b/sdk/lib/_internal/pub/test/transformer/dart2js/converts_entrypoint_in_web_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 'package:scheduled_test/scheduled_test.dart';
+
+import '../../descriptor.dart' as d;
+import '../../test_pub.dart';
+import '../../serve/utils.dart';
+
+main() {
+ initConfig();
+ integration("converts a Dart entrypoint in web to JS", () {
+ d.dir(appPath, [
+ d.appPubspec(),
+ d.dir("web", [
+ d.file("main.dart", "void main() => print('hello');")
+ ])
+ ]).create();
+
+ startPubServe();
+ requestShouldSucceed("main.dart.js", contains("hello"));
+ endPubServe();
+ });
+}
diff --git a/sdk/lib/_internal/pub/test/transformer/dart2js/ignores_entrypoint_in_dependency_test.dart b/sdk/lib/_internal/pub/test/transformer/dart2js/ignores_entrypoint_in_dependency_test.dart
new file mode 100644
index 0000000..10aa1c2
--- /dev/null
+++ b/sdk/lib/_internal/pub/test/transformer/dart2js/ignores_entrypoint_in_dependency_test.dart
@@ -0,0 +1,31 @@
+// 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 '../../descriptor.dart' as d;
+import '../../test_pub.dart';
+import '../../serve/utils.dart';
+
+main() {
+ initConfig();
+ integration("ignores a Dart entrypoint in a dependency", () {
+ d.dir("foo", [
+ d.libPubspec("foo", "0.0.1"),
+ d.dir("lib", [
+ d.file("lib.dart", "main() => print('foo');")
+ ])
+ ]).create();
+
+ d.dir(appPath, [
+ d.appPubspec({
+ "foo": {"path": "../foo"}
+ })
+ ]).create();
+
+ startPubServe(shouldInstallFirst: true);
+ requestShould404("web/packages/foo/lib.dart.js");
+ endPubServe();
+ });
+}
diff --git a/sdk/lib/_internal/pub/test/transformer/dart2js/ignores_entrypoint_outside_web_test.dart b/sdk/lib/_internal/pub/test/transformer/dart2js/ignores_entrypoint_outside_web_test.dart
new file mode 100644
index 0000000..baae7d4
--- /dev/null
+++ b/sdk/lib/_internal/pub/test/transformer/dart2js/ignores_entrypoint_outside_web_test.dart
@@ -0,0 +1,25 @@
+// 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 '../../descriptor.dart' as d;
+import '../../test_pub.dart';
+import '../../serve/utils.dart';
+
+main() {
+ initConfig();
+ integration("ignores a Dart entrypoint outside web", () {
+ d.dir(appPath, [
+ d.appPubspec(),
+ d.dir("lib", [
+ d.file("main.dart", "void main() => print('hello');")
+ ])
+ ]).create();
+
+ startPubServe();
+ requestShould404("packages/myapp/main.dart.js");
+ endPubServe();
+ });
+}
diff --git a/sdk/lib/_internal/pub/test/transformer/dart2js/ignores_nonentrypoint_in_web_test.dart b/sdk/lib/_internal/pub/test/transformer/dart2js/ignores_nonentrypoint_in_web_test.dart
new file mode 100644
index 0000000..f5922e6
--- /dev/null
+++ b/sdk/lib/_internal/pub/test/transformer/dart2js/ignores_nonentrypoint_in_web_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 '../../descriptor.dart' as d;
+import '../../test_pub.dart';
+import '../../serve/utils.dart';
+
+main() {
+ initConfig();
+ integration("ignores a non-entrypoint library in web", () {
+ d.dir(appPath, [
+ d.appPubspec(),
+ d.dir("web", [
+ d.file("notmain.dart", "foo() => print('hello');")
+ ])
+ ]).create();
+
+ startPubServe();
+ waitForBuildSuccess();
+ requestShouldSucceed("notmain.dart", "foo() => print('hello');");
+ requestShould404("notmain.dart.js");
+ endPubServe();
+ });
+}
diff --git a/sdk/lib/collection/collection.dart b/sdk/lib/collection/collection.dart
index ba07414..54085f7 100644
--- a/sdk/lib/collection/collection.dart
+++ b/sdk/lib/collection/collection.dart
@@ -8,6 +8,7 @@
library dart.collection;
import 'dart:_collection-dev';
+import 'dart:math' show Random; // Used by ListMixin.shuffle.
part 'collections.dart';
part 'iterable.dart';
diff --git a/sdk/lib/collection/list.dart b/sdk/lib/collection/list.dart
index 0e0c611..74cda1d 100644
--- a/sdk/lib/collection/list.dart
+++ b/sdk/lib/collection/list.dart
@@ -301,6 +301,18 @@
Sort.sort(this, compare);
}
+ void shuffle() {
+ Random random = new Random();
+ int length = this.length;
+ while (length > 1) {
+ int pos = random.nextInt(length);
+ length -= 1;
+ var tmp = this[length];
+ this[length] = this[pos];
+ this[pos] = tmp;
+ }
+ }
+
Map<int, E> asMap() {
return new ListMapView(this);
}
diff --git a/sdk/lib/collection/queue.dart b/sdk/lib/collection/queue.dart
index 02405b8..1cacd18 100644
--- a/sdk/lib/collection/queue.dart
+++ b/sdk/lib/collection/queue.dart
@@ -74,9 +74,6 @@
/**
* An entry in a doubly linked list. It contains a pointer to the next
* entry, the previous entry, and the boxed element.
- *
- * WARNING: This class is temporary located in dart:core. It'll be removed
- * at some point in the near future.
*/
class DoubleLinkedQueueEntry<E> {
DoubleLinkedQueueEntry<E> _previous;
diff --git a/sdk/lib/core/list.dart b/sdk/lib/core/list.dart
index a0473cb..5d5132e 100644
--- a/sdk/lib/core/list.dart
+++ b/sdk/lib/core/list.dart
@@ -182,6 +182,11 @@
void sort([int compare(E a, E b)]);
/**
+ * Shuffles the elements of this list randomly.
+ */
+ void shuffle();
+
+ /**
* Returns the first index of [element] in this list.
*
* Searches the list from index [start] to the end of the list.
diff --git a/sdk/lib/html/dart2js/html_dart2js.dart b/sdk/lib/html/dart2js/html_dart2js.dart
index 6c9cfd9..3641bda 100644
--- a/sdk/lib/html/dart2js/html_dart2js.dart
+++ b/sdk/lib/html/dart2js/html_dart2js.dart
@@ -57,6 +57,8 @@
Interceptor, JSExtendableArray, findInterceptorConstructorForType,
getNativeInterceptor;
+export 'dart:math' show Rectangle, Point;
+
@@ -1583,19 +1585,19 @@
* img.height = 100;
*
* // Scale the image to 20x20.
- * ctx.drawImageToRect(img, new Rect(50, 50, 20, 20));
+ * ctx.drawImageToRect(img, new Rectangle(50, 50, 20, 20));
*
* VideoElement video = document.query('video');
* video.width = 100;
* video.height = 100;
* // Take the middle 20x20 pixels from the video and stretch them.
- * ctx.drawImageToRect(video, new Rect(50, 50, 100, 100),
- * sourceRect: new Rect(40, 40, 20, 20));
+ * ctx.drawImageToRect(video, new Rectangle(50, 50, 100, 100),
+ * sourceRect: new Rectangle(40, 40, 20, 20));
*
* // Draw the top 100x20 pixels from the otherCanvas.
* CanvasElement otherCanvas = document.query('canvas');
- * ctx.drawImageToRect(otherCanvas, new Rect(0, 0, 100, 20),
- * sourceRect: new Rect(0, 0, 100, 20));
+ * ctx.drawImageToRect(otherCanvas, new Rectangle(0, 0, 100, 20),
+ * sourceRect: new Rectangle(0, 0, 100, 20));
*
* See also:
*
@@ -1605,8 +1607,8 @@
* from the WHATWG.
*/
@DomName('CanvasRenderingContext2D.drawImage')
- void drawImageToRect(CanvasImageSource source, Rect destRect,
- {Rect sourceRect}) {
+ void drawImageToRect(CanvasImageSource source, Rectangle destRect,
+ {Rectangle sourceRect}) {
if (sourceRect == null) {
drawImageScaled(source,
destRect.left,
@@ -8166,6 +8168,10 @@
throw new UnsupportedError('Cannot sort element lists');
}
+ void shuffle() {
+ throw new UnsupportedError('Cannot shuffle element lists');
+ }
+
void removeWhere(bool test(Element element)) {
_filter(test, false);
}
@@ -8611,6 +8617,10 @@
throw new UnsupportedError('Cannot sort list');
}
+ void shuffle() {
+ throw new UnsupportedError('Cannot shuffle list');
+ }
+
Element get first => _nodeList.first;
Element get last => _nodeList.last;
@@ -9232,12 +9242,14 @@
/**
* Gets the position of this element relative to the client area of the page.
*/
- Rect get client => new Rect(clientLeft, clientTop, clientWidth, clientHeight);
+ Rectangle get client => new Rectangle(clientLeft, clientTop, clientWidth,
+ clientHeight);
/**
* Gets the offset of this element relative to its offsetParent.
*/
- Rect get offset => new Rect(offsetLeft, offsetTop, offsetWidth, offsetHeight);
+ Rectangle get offset => new Rectangle(offsetLeft, offsetTop, offsetWidth,
+ offsetHeight);
/**
* Adds the specified text after the last child of this element.
@@ -10325,13 +10337,13 @@
@DomName('Element.getBoundingClientRect')
@DocsEditable()
- Rect getBoundingClientRect() native;
+ Rectangle getBoundingClientRect() native;
@DomName('Element.getClientRects')
@DocsEditable()
@Returns('_ClientRectList')
@Creates('_ClientRectList')
- List<Rect> getClientRects() native;
+ List<Rectangle> getClientRects() native;
@DomName('Element.getDestinationInsertionPoints')
@DocsEditable()
@@ -17181,7 +17193,8 @@
'offsetX is only supported on elements');
}
Element target = this.target;
- return (this.client - target.getBoundingClientRect().topLeft).toInt();
+ var point = (this.client - target.getBoundingClientRect().topLeft);
+ return new Point(point.x.toInt(), point.y.toInt());
}
}
@@ -17917,6 +17930,10 @@
throw new UnsupportedError("Cannot sort Node list");
}
+ void shuffle() {
+ throw new UnsupportedError("Cannot shuffle Node list");
+ }
+
// FIXME: implement these.
void setRange(int start, int end, Iterable<Node> iterable,
[int skipCount = 0]) {
@@ -20015,13 +20032,13 @@
@DomName('Range.getBoundingClientRect')
@DocsEditable()
- Rect getBoundingClientRect() native;
+ Rectangle getBoundingClientRect() native;
@DomName('Range.getClientRects')
@DocsEditable()
@Returns('_ClientRectList')
@Creates('_ClientRectList')
- List<Rect> getClientRects() native;
+ List<Rectangle> getClientRects() native;
@DomName('Range.insertNode')
@DocsEditable()
@@ -20825,7 +20842,7 @@
@DomName('Screen.availLeft')
@DomName('Screen.availTop')
@DomName('Screen.availWidth')
- Rect get available => new Rect(_availLeft, _availTop, _availWidth,
+ Rectangle get available => new Rectangle(_availLeft, _availTop, _availWidth,
_availHeight);
@JSName('availHeight')
@@ -26951,38 +26968,41 @@
@DocsEditable()
@DomName('ClientRect')
-class _ClientRect extends Interceptor implements Rect native "ClientRect" {
+class _ClientRect extends Interceptor implements Rectangle native "ClientRect" {
- // NOTE! All code below should be common with Rect.
- // TODO(blois): implement with mixins when available.
-
- String toString() {
- return '($left, $top, $width, $height)';
+ // NOTE! All code below should be common with RectangleBase.
+ String toString() {
+ return 'Rectangle ($left, $top) $width x $height';
}
bool operator ==(other) {
- if (other is !Rect) return false;
+ if (other is !Rectangle) return false;
return left == other.left && top == other.top && width == other.width &&
height == other.height;
}
- int get hashCode => JenkinsSmiHash.hash4(left.hashCode, top.hashCode,
+ int get hashCode => _JenkinsSmiHash.hash4(left.hashCode, top.hashCode,
width.hashCode, height.hashCode);
/**
- * Computes the intersection of this rectangle and the rectangle parameter.
- * Returns null if there is no intersection.
+ * Computes the intersection of `this` and [other].
+ *
+ * The intersection of two axis-aligned rectangles, if any, is always another
+ * axis-aligned rectangle.
+ *
+ * Returns the intersection of this and `other`, or `null` if they don't
+ * intersect.
*/
- Rect intersection(Rect rect) {
- var x0 = max(left, rect.left);
- var x1 = min(left + width, rect.left + rect.width);
+ Rectangle intersection(Rectangle other) {
+ var x0 = max(left, other.left);
+ var x1 = min(left + width, other.left + other.width);
if (x0 <= x1) {
- var y0 = max(top, rect.top);
- var y1 = min(top + height, rect.top + rect.height);
+ var y0 = max(top, other.top);
+ var y1 = min(top + height, other.top + other.height);
if (y0 <= y1) {
- return new Rect(x0, y0, x1 - x0, y1 - y0);
+ return new Rectangle(x0, y0, x1 - x0, y1 - y0);
}
}
return null;
@@ -26990,31 +27010,32 @@
/**
- * Returns whether a rectangle intersects this rectangle.
+ * Returns true if `this` intersects [other].
*/
- bool intersects(Rect other) {
- return (left <= other.left + other.width && other.left <= left + width &&
- top <= other.top + other.height && other.top <= top + height);
+ bool intersects(Rectangle<num> other) {
+ return (left <= other.left + other.width &&
+ other.left <= left + width &&
+ top <= other.top + other.height &&
+ other.top <= top + height);
}
/**
- * Returns a new rectangle which completely contains this rectangle and the
- * input rectangle.
+ * Returns a new rectangle which completely contains `this` and [other].
*/
- Rect union(Rect rect) {
- var right = max(this.left + this.width, rect.left + rect.width);
- var bottom = max(this.top + this.height, rect.top + rect.height);
+ Rectangle boundingBox(Rectangle other) {
+ var right = max(this.left + this.width, other.left + other.width);
+ var bottom = max(this.top + this.height, other.top + other.height);
- var left = min(this.left, rect.left);
- var top = min(this.top, rect.top);
+ var left = min(this.left, other.left);
+ var top = min(this.top, other.top);
- return new Rect(left, top, right - left, bottom - top);
+ return new Rectangle(left, top, right - left, bottom - top);
}
/**
- * Tests whether this rectangle entirely contains another rectangle.
+ * Tests whether `this` entirely contains [another].
*/
- bool containsRect(Rect another) {
+ bool contains(Rectangle<num> another) {
return left <= another.left &&
left + width >= another.left + another.width &&
top <= another.top &&
@@ -27022,32 +27043,23 @@
}
/**
- * Tests whether this rectangle entirely contains a point.
+ * Tests whether [another] is inside or along the edges of `this`.
*/
- bool containsPoint(Point another) {
+ bool containsPoint(Point<num> another) {
return another.x >= left &&
another.x <= left + width &&
another.y >= top &&
another.y <= top + height;
}
- Rect ceil() => new Rect(left.ceil(), top.ceil(), width.ceil(), height.ceil());
- Rect floor() => new Rect(left.floor(), top.floor(), width.floor(),
- height.floor());
- Rect round() => new Rect(left.round(), top.round(), width.round(),
- height.round());
-
- /**
- * Truncates coordinates to integers and returns the result as a new
- * rectangle.
- */
- Rect toInt() => new Rect(left.toInt(), top.toInt(), width.toInt(),
- height.toInt());
-
Point get topLeft => new Point(this.left, this.top);
+ Point get topRight => new Point(this.left + this.width, this.top);
Point get bottomRight => new Point(this.left + this.width,
this.top + this.height);
+ Point get bottomLeft => new Point(this.left,
+ this.top + this.height);
+
@DomName('ClientRect.bottom')
@DocsEditable()
final double bottom;
@@ -27072,6 +27084,43 @@
@DocsEditable()
final double width;
}
+
+/**
+ * This is the [Jenkins hash function][1] but using masking to keep
+ * values in SMI range.
+ *
+ * [1]: http://en.wikipedia.org/wiki/Jenkins_hash_function
+ *
+ * Use:
+ * Hash each value with the hash of the previous value, then get the final
+ * hash by calling finish.
+ *
+ * var hash = 0;
+ * for (var value in values) {
+ * hash = JenkinsSmiHash.combine(hash, value.hashCode);
+ * }
+ * hash = JenkinsSmiHash.finish(hash);
+ */
+class _JenkinsSmiHash {
+ // TODO(11617): This class should be optimized and standardized elsewhere.
+
+ static int combine(int hash, int value) {
+ hash = 0x1fffffff & (hash + value);
+ hash = 0x1fffffff & (hash + ((0x0007ffff & hash) << 10));
+ return hash ^ (hash >> 6);
+ }
+
+ static int finish(int hash) {
+ hash = 0x1fffffff & (hash + ((0x03ffffff & hash) << 3));
+ hash = hash ^ (hash >> 11);
+ return 0x1fffffff & (hash + ((0x00003fff & hash) << 15));
+ }
+
+ static int hash2(a, b) => finish(combine(combine(0, a), b));
+
+ static int hash4(a, b, c, d) =>
+ finish(combine(combine(combine(combine(0, a), b), c), d));
+}
// 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.
@@ -27079,59 +27128,59 @@
@DocsEditable()
@DomName('ClientRectList')
-class _ClientRectList extends Interceptor with ListMixin<Rect>, ImmutableListMixin<Rect> implements JavaScriptIndexingBehavior, List<Rect> native "ClientRectList" {
+class _ClientRectList extends Interceptor with ListMixin<Rectangle>, ImmutableListMixin<Rectangle> implements List<Rectangle>, JavaScriptIndexingBehavior native "ClientRectList" {
@DomName('ClientRectList.length')
@DocsEditable()
int get length => JS("int", "#.length", this);
- Rect operator[](int index) {
+ Rectangle operator[](int index) {
if (JS("bool", "# >>> 0 !== # || # >= #", index,
index, index, length))
throw new RangeError.range(index, 0, length);
- return JS("Rect", "#[#]", this, index);
+ return JS("Rectangle", "#[#]", this, index);
}
- void operator[]=(int index, Rect value) {
+ void operator[]=(int index, Rectangle value) {
throw new UnsupportedError("Cannot assign element of immutable List.");
}
- // -- start List<Rect> mixins.
- // Rect is the element type.
+ // -- start List<Rectangle> mixins.
+ // Rectangle is the element type.
void set length(int value) {
throw new UnsupportedError("Cannot resize immutable List.");
}
- Rect get first {
+ Rectangle get first {
if (this.length > 0) {
- return JS('Rect', '#[0]', this);
+ return JS('Rectangle', '#[0]', this);
}
throw new StateError("No elements");
}
- Rect get last {
+ Rectangle get last {
int len = this.length;
if (len > 0) {
- return JS('Rect', '#[#]', this, len - 1);
+ return JS('Rectangle', '#[#]', this, len - 1);
}
throw new StateError("No elements");
}
- Rect get single {
+ Rectangle get single {
int len = this.length;
if (len == 1) {
- return JS('Rect', '#[0]', this);
+ return JS('Rectangle', '#[0]', this);
}
if (len == 0) throw new StateError("No elements");
throw new StateError("More than one element");
}
- Rect elementAt(int index) => this[index];
- // -- end List<Rect> mixins.
+ Rectangle elementAt(int index) => this[index];
+ // -- end List<Rectangle> mixins.
@DomName('ClientRectList.item')
@DocsEditable()
- Rect item(int index) native;
+ Rectangle item(int index) 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
@@ -28767,18 +28816,19 @@
/**
* A class for representing CSS dimensions.
*
- * In contrast to the more general purpose [Rect] class, this class's values are
- * mutable, so one can change the height of an element programmatically.
+ * In contrast to the more general purpose [Rectangle] class, this class's
+ * values are mutable, so one can change the height of an element
+ * programmatically.
*
* _Important_ _note_: use of these methods will perform CSS calculations that
* can trigger a browser reflow. Therefore, use of these properties _during_ an
* animation frame is discouraged. See also:
* [Browser Reflow](https://developers.google.com/speed/articles/reflow)
*/
-abstract class CssRect extends RectBase implements Rect {
+abstract class CssRect extends MutableRectangle<num> implements Rectangle<num> {
Element _element;
- CssRect(this._element);
+ CssRect(this._element) : super(0, 0, 0, 0);
num get left;
@@ -29778,6 +29828,10 @@
throw new UnsupportedError("Cannot sort immutable List.");
}
+ void shuffle() {
+ throw new UnsupportedError("Cannot shuffle immutable List.");
+ }
+
void insert(int index, E element) {
throw new UnsupportedError("Cannot add to immutable List.");
}
@@ -31279,7 +31333,7 @@
* Scheduler which uses window.postMessage to schedule events.
*/
class _PostMessageScheduler extends _MicrotaskScheduler {
- const _MICROTASK_MESSAGE = "DART-MICROTASK";
+ final _MICROTASK_MESSAGE = "DART-MICROTASK";
_PostMessageScheduler(_MicrotaskCallback callback): super(callback) {
// Messages from other windows do not cause a security risk as
@@ -31839,77 +31893,6 @@
return allowsElement(element);
}
}
-// 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.
-
-
-/**
- * A utility class for representing two-dimensional positions.
- */
-class Point {
- final num x;
- final num y;
-
- const Point([num x = 0, num y = 0]): x = x, y = y;
-
- String toString() => '($x, $y)';
-
- bool operator ==(other) {
- if (other is !Point) return false;
- return x == other.x && y == other.y;
- }
-
- int get hashCode => JenkinsSmiHash.hash2(x.hashCode, y.hashCode);
-
- Point operator +(Point other) {
- return new Point(x + other.x, y + other.y);
- }
-
- Point operator -(Point other) {
- return new Point(x - other.x, y - other.y);
- }
-
- Point operator *(num factor) {
- return new Point(x * factor, y * factor);
- }
-
- /**
- * Get the straight line (Euclidean) distance between the origin (0, 0) and
- * this point.
- */
- num get magnitude => sqrt(x * x + y * y);
-
- /**
- * Returns the distance between two points.
- */
- double distanceTo(Point other) {
- var dx = x - other.x;
- var dy = y - other.y;
- return sqrt(dx * dx + dy * dy);
- }
-
- /**
- * Returns the squared distance between two points.
- *
- * Squared distances can be used for comparisons when the actual value is not
- * required.
- */
- num squaredDistanceTo(Point other) {
- var dx = x - other.x;
- var dy = y - other.y;
- return dx * dx + dy * dy;
- }
-
- Point ceil() => new Point(x.ceil(), y.ceil());
- Point floor() => new Point(x.floor(), y.floor());
- Point round() => new Point(x.round(), y.round());
-
- /**
- * Truncates x and y to integers and returns the result as a new point.
- */
- Point toInt() => new Point(x.toInt(), y.toInt());
-}
// Copyright (c) 2011, 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.
@@ -31935,163 +31918,6 @@
*/
static const String COMPLETE = "complete";
}
-// 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.
-
-
-/**
- * A base class for representing two-dimensional rectangles. This will hopefully
- * be moved merged with the dart:math Rect.
- */
-// TODO(efortuna): Merge with Math rect after finalizing with Florian.
-abstract class RectBase {
- // Not used, but keeps the VM from complaining about Rect having a const
- // constructor and this one not.
- const RectBase();
-
- num get left;
- num get top;
- num get width;
- num get height;
-
- num get right => left + width;
- num get bottom => top + height;
-
- // NOTE! All code below should be common with Rect.
-
- String toString() {
- return '($left, $top, $width, $height)';
- }
-
- bool operator ==(other) {
- if (other is !Rect) return false;
- return left == other.left && top == other.top && width == other.width &&
- height == other.height;
- }
-
- int get hashCode => JenkinsSmiHash.hash4(left.hashCode, top.hashCode,
- width.hashCode, height.hashCode);
-
- /**
- * Computes the intersection of this rectangle and the rectangle parameter.
- * Returns null if there is no intersection.
- */
- Rect intersection(Rect rect) {
- var x0 = max(left, rect.left);
- var x1 = min(left + width, rect.left + rect.width);
-
- if (x0 <= x1) {
- var y0 = max(top, rect.top);
- var y1 = min(top + height, rect.top + rect.height);
-
- if (y0 <= y1) {
- return new Rect(x0, y0, x1 - x0, y1 - y0);
- }
- }
- return null;
- }
-
-
- /**
- * Returns whether a rectangle intersects this rectangle.
- */
- bool intersects(Rect other) {
- return (left <= other.left + other.width && other.left <= left + width &&
- top <= other.top + other.height && other.top <= top + height);
- }
-
- /**
- * Returns a new rectangle which completely contains this rectangle and the
- * input rectangle.
- */
- Rect union(Rect rect) {
- var right = max(this.left + this.width, rect.left + rect.width);
- var bottom = max(this.top + this.height, rect.top + rect.height);
-
- var left = min(this.left, rect.left);
- var top = min(this.top, rect.top);
-
- return new Rect(left, top, right - left, bottom - top);
- }
-
- /**
- * Tests whether this rectangle entirely contains another rectangle.
- */
- bool containsRect(Rect another) {
- return left <= another.left &&
- left + width >= another.left + another.width &&
- top <= another.top &&
- top + height >= another.top + another.height;
- }
-
- /**
- * Tests whether this rectangle entirely contains a point.
- */
- bool containsPoint(Point another) {
- return another.x >= left &&
- another.x <= left + width &&
- another.y >= top &&
- another.y <= top + height;
- }
-
- Rect ceil() => new Rect(left.ceil(), top.ceil(), width.ceil(), height.ceil());
- Rect floor() => new Rect(left.floor(), top.floor(), width.floor(),
- height.floor());
- Rect round() => new Rect(left.round(), top.round(), width.round(),
- height.round());
-
- /**
- * Truncates coordinates to integers and returns the result as a new
- * rectangle.
- */
- Rect toInt() => new Rect(left.toInt(), top.toInt(), width.toInt(),
- height.toInt());
-
- Point get topLeft => new Point(this.left, this.top);
- Point get bottomRight => new Point(this.left + this.width,
- this.top + this.height);
-}
-
-
-
-/**
- * A class for representing two-dimensional rectangles.
- *
- * This class is distinctive from RectBase in that it enforces that its
- * properties are immutable.
- */
-class Rect extends RectBase {
- final num left;
- final num top;
- final num width;
- final num height;
-
- const Rect(this.left, this.top, this.width, this.height): super();
-
- factory Rect.fromPoints(Point a, Point b) {
- var left;
- var width;
- if (a.x < b.x) {
- left = a.x;
- width = b.x - left;
- } else {
- left = b.x;
- width = a.x - left;
- }
- var top;
- var height;
- if (a.y < b.y) {
- top = a.y;
- height = b.y - top;
- } else {
- top = b.y;
- height = a.y - top;
- }
-
- return new Rect(left, top, width, height);
- }
-}
// 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.
diff --git a/sdk/lib/html/dartium/html_dartium.dart b/sdk/lib/html/dartium/html_dartium.dart
index c9879ea..5c69f2c 100644
--- a/sdk/lib/html/dartium/html_dartium.dart
+++ b/sdk/lib/html/dartium/html_dartium.dart
@@ -51,6 +51,8 @@
// native code for custom elements.
// Not actually used, but imported since dart:html can generate these objects.
+export 'dart:math' show Rectangle, RectangleBase, Point;
+
@@ -1922,19 +1924,19 @@
* img.height = 100;
*
* // Scale the image to 20x20.
- * ctx.drawImageToRect(img, new Rect(50, 50, 20, 20));
+ * ctx.drawImageToRect(img, new Rectangle(50, 50, 20, 20));
*
* VideoElement video = document.query('video');
* video.width = 100;
* video.height = 100;
* // Take the middle 20x20 pixels from the video and stretch them.
- * ctx.drawImageToRect(video, new Rect(50, 50, 100, 100),
- * sourceRect: new Rect(40, 40, 20, 20));
+ * ctx.drawImageToRect(video, new Rectangle(50, 50, 100, 100),
+ * sourceRect: new Rectangle(40, 40, 20, 20));
*
* // Draw the top 100x20 pixels from the otherCanvas.
* CanvasElement otherCanvas = document.query('canvas');
- * ctx.drawImageToRect(otherCanvas, new Rect(0, 0, 100, 20),
- * sourceRect: new Rect(0, 0, 100, 20));
+ * ctx.drawImageToRect(otherCanvas, new Rectangle(0, 0, 100, 20),
+ * sourceRect: new Rectangle(0, 0, 100, 20));
*
* See also:
*
@@ -1944,8 +1946,8 @@
* from the WHATWG.
*/
@DomName('CanvasRenderingContext2D.drawImage')
- void drawImageToRect(CanvasImageSource source, Rect destRect,
- {Rect sourceRect}) {
+ void drawImageToRect(CanvasImageSource source, Rectangle destRect,
+ {Rectangle sourceRect}) {
if (sourceRect == null) {
_drawImage(source,
destRect.left,
@@ -8722,6 +8724,10 @@
throw new UnsupportedError('Cannot sort element lists');
}
+ void shuffle() {
+ throw new UnsupportedError('Cannot shuffle element lists');
+ }
+
void removeWhere(bool test(Element element)) {
_filter(test, false);
}
@@ -9167,6 +9173,10 @@
throw new UnsupportedError('Cannot sort list');
}
+ void shuffle() {
+ throw new UnsupportedError('Cannot shuffle list');
+ }
+
Element get first => _nodeList.first;
Element get last => _nodeList.last;
@@ -9788,12 +9798,14 @@
/**
* Gets the position of this element relative to the client area of the page.
*/
- Rect get client => new Rect(clientLeft, clientTop, clientWidth, clientHeight);
+ Rectangle get client => new Rectangle(clientLeft, clientTop, clientWidth,
+ clientHeight);
/**
* Gets the offset of this element relative to its offsetParent.
*/
- Rect get offset => new Rect(offsetLeft, offsetTop, offsetWidth, offsetHeight);
+ Rectangle get offset => new Rectangle(offsetLeft, offsetTop, offsetWidth,
+ offsetHeight);
/**
* Adds the specified text after the last child of this element.
@@ -10727,11 +10739,11 @@
@DomName('Element.getBoundingClientRect')
@DocsEditable()
- Rect getBoundingClientRect() native "Element_getBoundingClientRect_Callback";
+ Rectangle getBoundingClientRect() native "Element_getBoundingClientRect_Callback";
@DomName('Element.getClientRects')
@DocsEditable()
- List<Rect> getClientRects() native "Element_getClientRects_Callback";
+ List<Rectangle> getClientRects() native "Element_getClientRects_Callback";
@DomName('Element.getDestinationInsertionPoints')
@DocsEditable()
@@ -19227,6 +19239,10 @@
throw new UnsupportedError("Cannot sort Node list");
}
+ void shuffle() {
+ throw new UnsupportedError("Cannot shuffle Node list");
+ }
+
// FIXME: implement these.
void setRange(int start, int end, Iterable<Node> iterable,
[int skipCount = 0]) {
@@ -21555,11 +21571,11 @@
@DomName('Range.getBoundingClientRect')
@DocsEditable()
- Rect getBoundingClientRect() native "Range_getBoundingClientRect_Callback";
+ Rectangle getBoundingClientRect() native "Range_getBoundingClientRect_Callback";
@DomName('Range.getClientRects')
@DocsEditable()
- List<Rect> getClientRects() native "Range_getClientRects_Callback";
+ List<Rectangle> getClientRects() native "Range_getClientRects_Callback";
@DomName('Range.insertNode')
@DocsEditable()
@@ -22360,7 +22376,7 @@
@DomName('Screen.availLeft')
@DomName('Screen.availTop')
@DomName('Screen.availWidth')
- Rect get available => new Rect(_availLeft, _availTop, _availWidth,
+ Rectangle get available => new Rectangle(_availLeft, _availTop, _availWidth,
_availHeight);
@DomName('Screen.availHeight')
@@ -26535,13 +26551,13 @@
if ((blob_OR_source_OR_stream is Blob || blob_OR_source_OR_stream == null)) {
return _createObjectURL_1(blob_OR_source_OR_stream);
}
- if ((blob_OR_source_OR_stream is MediaStream || blob_OR_source_OR_stream == null)) {
+ if ((blob_OR_source_OR_stream is MediaSource || blob_OR_source_OR_stream == null)) {
return _createObjectURL_2(blob_OR_source_OR_stream);
}
- if ((blob_OR_source_OR_stream is MediaSource || blob_OR_source_OR_stream == null)) {
+ if ((blob_OR_source_OR_stream is _WebKitMediaSource || blob_OR_source_OR_stream == null)) {
return _createObjectURL_3(blob_OR_source_OR_stream);
}
- if ((blob_OR_source_OR_stream is _WebKitMediaSource || blob_OR_source_OR_stream == null)) {
+ if ((blob_OR_source_OR_stream is MediaStream || blob_OR_source_OR_stream == null)) {
return _createObjectURL_4(blob_OR_source_OR_stream);
}
throw new ArgumentError("Incorrect number or type of arguments");
@@ -28907,38 +28923,41 @@
@DocsEditable()
@DomName('ClientRect')
-class _ClientRect extends NativeFieldWrapperClass1 implements Rect {
+class _ClientRect extends NativeFieldWrapperClass1 implements Rectangle {
- // NOTE! All code below should be common with Rect.
- // TODO(blois): implement with mixins when available.
-
- String toString() {
- return '($left, $top, $width, $height)';
+ // NOTE! All code below should be common with RectangleBase.
+ String toString() {
+ return 'Rectangle ($left, $top) $width x $height';
}
bool operator ==(other) {
- if (other is !Rect) return false;
+ if (other is !Rectangle) return false;
return left == other.left && top == other.top && width == other.width &&
height == other.height;
}
- int get hashCode => JenkinsSmiHash.hash4(left.hashCode, top.hashCode,
+ int get hashCode => _JenkinsSmiHash.hash4(left.hashCode, top.hashCode,
width.hashCode, height.hashCode);
/**
- * Computes the intersection of this rectangle and the rectangle parameter.
- * Returns null if there is no intersection.
+ * Computes the intersection of `this` and [other].
+ *
+ * The intersection of two axis-aligned rectangles, if any, is always another
+ * axis-aligned rectangle.
+ *
+ * Returns the intersection of this and `other`, or `null` if they don't
+ * intersect.
*/
- Rect intersection(Rect rect) {
- var x0 = max(left, rect.left);
- var x1 = min(left + width, rect.left + rect.width);
+ Rectangle intersection(Rectangle other) {
+ var x0 = max(left, other.left);
+ var x1 = min(left + width, other.left + other.width);
if (x0 <= x1) {
- var y0 = max(top, rect.top);
- var y1 = min(top + height, rect.top + rect.height);
+ var y0 = max(top, other.top);
+ var y1 = min(top + height, other.top + other.height);
if (y0 <= y1) {
- return new Rect(x0, y0, x1 - x0, y1 - y0);
+ return new Rectangle(x0, y0, x1 - x0, y1 - y0);
}
}
return null;
@@ -28946,31 +28965,32 @@
/**
- * Returns whether a rectangle intersects this rectangle.
+ * Returns true if `this` intersects [other].
*/
- bool intersects(Rect other) {
- return (left <= other.left + other.width && other.left <= left + width &&
- top <= other.top + other.height && other.top <= top + height);
+ bool intersects(Rectangle<num> other) {
+ return (left <= other.left + other.width &&
+ other.left <= left + width &&
+ top <= other.top + other.height &&
+ other.top <= top + height);
}
/**
- * Returns a new rectangle which completely contains this rectangle and the
- * input rectangle.
+ * Returns a new rectangle which completely contains `this` and [other].
*/
- Rect union(Rect rect) {
- var right = max(this.left + this.width, rect.left + rect.width);
- var bottom = max(this.top + this.height, rect.top + rect.height);
+ Rectangle boundingBox(Rectangle other) {
+ var right = max(this.left + this.width, other.left + other.width);
+ var bottom = max(this.top + this.height, other.top + other.height);
- var left = min(this.left, rect.left);
- var top = min(this.top, rect.top);
+ var left = min(this.left, other.left);
+ var top = min(this.top, other.top);
- return new Rect(left, top, right - left, bottom - top);
+ return new Rectangle(left, top, right - left, bottom - top);
}
/**
- * Tests whether this rectangle entirely contains another rectangle.
+ * Tests whether `this` entirely contains [another].
*/
- bool containsRect(Rect another) {
+ bool contains(Rectangle<num> another) {
return left <= another.left &&
left + width >= another.left + another.width &&
top <= another.top &&
@@ -28978,32 +28998,23 @@
}
/**
- * Tests whether this rectangle entirely contains a point.
+ * Tests whether [another] is inside or along the edges of `this`.
*/
- bool containsPoint(Point another) {
+ bool containsPoint(Point<num> another) {
return another.x >= left &&
another.x <= left + width &&
another.y >= top &&
another.y <= top + height;
}
- Rect ceil() => new Rect(left.ceil(), top.ceil(), width.ceil(), height.ceil());
- Rect floor() => new Rect(left.floor(), top.floor(), width.floor(),
- height.floor());
- Rect round() => new Rect(left.round(), top.round(), width.round(),
- height.round());
-
- /**
- * Truncates coordinates to integers and returns the result as a new
- * rectangle.
- */
- Rect toInt() => new Rect(left.toInt(), top.toInt(), width.toInt(),
- height.toInt());
-
Point get topLeft => new Point(this.left, this.top);
+ Point get topRight => new Point(this.left + this.width, this.top);
Point get bottomRight => new Point(this.left + this.width,
this.top + this.height);
+ Point get bottomLeft => new Point(this.left,
+ this.top + this.height);
+
@DomName('ClientRect.bottom')
@DocsEditable()
double get bottom native "ClientRect_bottom_Getter";
@@ -29028,6 +29039,43 @@
@DocsEditable()
double get width native "ClientRect_width_Getter";
}
+
+/**
+ * This is the [Jenkins hash function][1] but using masking to keep
+ * values in SMI range.
+ *
+ * [1]: http://en.wikipedia.org/wiki/Jenkins_hash_function
+ *
+ * Use:
+ * Hash each value with the hash of the previous value, then get the final
+ * hash by calling finish.
+ *
+ * var hash = 0;
+ * for (var value in values) {
+ * hash = JenkinsSmiHash.combine(hash, value.hashCode);
+ * }
+ * hash = JenkinsSmiHash.finish(hash);
+ */
+class _JenkinsSmiHash {
+ // TODO(11617): This class should be optimized and standardized elsewhere.
+
+ static int combine(int hash, int value) {
+ hash = 0x1fffffff & (hash + value);
+ hash = 0x1fffffff & (hash + ((0x0007ffff & hash) << 10));
+ return hash ^ (hash >> 6);
+ }
+
+ static int finish(int hash) {
+ hash = 0x1fffffff & (hash + ((0x03ffffff & hash) << 3));
+ hash = hash ^ (hash >> 11);
+ return 0x1fffffff & (hash + ((0x00003fff & hash) << 15));
+ }
+
+ static int hash2(a, b) => finish(combine(combine(0, a), b));
+
+ static int hash4(a, b, c, d) =>
+ finish(combine(combine(combine(combine(0, a), b), c), d));
+}
// 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.
@@ -29037,38 +29085,38 @@
@DocsEditable()
@DomName('ClientRectList')
-class _ClientRectList extends NativeFieldWrapperClass1 with ListMixin<Rect>, ImmutableListMixin<Rect> implements List<Rect> {
+class _ClientRectList extends NativeFieldWrapperClass1 with ListMixin<Rectangle>, ImmutableListMixin<Rectangle> implements List<Rectangle> {
@DomName('ClientRectList.length')
@DocsEditable()
int get length native "ClientRectList_length_Getter";
- Rect operator[](int index) {
+ Rectangle operator[](int index) {
if (index < 0 || index >= length)
throw new RangeError.range(index, 0, length);
return _nativeIndexedGetter(index);
}
- Rect _nativeIndexedGetter(int index) native "ClientRectList_item_Callback";
+ Rectangle _nativeIndexedGetter(int index) native "ClientRectList_item_Callback";
- void operator[]=(int index, Rect value) {
+ void operator[]=(int index, Rectangle value) {
throw new UnsupportedError("Cannot assign element of immutable List.");
}
- // -- start List<Rect> mixins.
- // Rect is the element type.
+ // -- start List<Rectangle> mixins.
+ // Rectangle is the element type.
void set length(int value) {
throw new UnsupportedError("Cannot resize immutable List.");
}
- Rect get first {
+ Rectangle get first {
if (this.length > 0) {
return _nativeIndexedGetter(0);
}
throw new StateError("No elements");
}
- Rect get last {
+ Rectangle get last {
int len = this.length;
if (len > 0) {
return _nativeIndexedGetter(len - 1);
@@ -29076,7 +29124,7 @@
throw new StateError("No elements");
}
- Rect get single {
+ Rectangle get single {
int len = this.length;
if (len == 1) {
return _nativeIndexedGetter(0);
@@ -29085,12 +29133,12 @@
throw new StateError("More than one element");
}
- Rect elementAt(int index) => this[index];
- // -- end List<Rect> mixins.
+ Rectangle elementAt(int index) => this[index];
+ // -- end List<Rectangle> mixins.
@DomName('ClientRectList.item')
@DocsEditable()
- Rect item(int index) native "ClientRectList_item_Callback";
+ Rectangle item(int index) native "ClientRectList_item_Callback";
}
// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
@@ -30849,18 +30897,19 @@
/**
* A class for representing CSS dimensions.
*
- * In contrast to the more general purpose [Rect] class, this class's values are
- * mutable, so one can change the height of an element programmatically.
+ * In contrast to the more general purpose [Rectangle] class, this class's
+ * values are mutable, so one can change the height of an element
+ * programmatically.
*
* _Important_ _note_: use of these methods will perform CSS calculations that
* can trigger a browser reflow. Therefore, use of these properties _during_ an
* animation frame is discouraged. See also:
* [Browser Reflow](https://developers.google.com/speed/articles/reflow)
*/
-abstract class CssRect extends RectBase implements Rect {
+abstract class CssRect extends MutableRectangle<num> implements Rectangle<num> {
Element _element;
- CssRect(this._element);
+ CssRect(this._element) : super(0, 0, 0, 0);
num get left;
@@ -31860,6 +31909,10 @@
throw new UnsupportedError("Cannot sort immutable List.");
}
+ void shuffle() {
+ throw new UnsupportedError("Cannot shuffle immutable List.");
+ }
+
void insert(int index, E element) {
throw new UnsupportedError("Cannot add to immutable List.");
}
@@ -33361,7 +33414,7 @@
* Scheduler which uses window.postMessage to schedule events.
*/
class _PostMessageScheduler extends _MicrotaskScheduler {
- const _MICROTASK_MESSAGE = "DART-MICROTASK";
+ final _MICROTASK_MESSAGE = "DART-MICROTASK";
_PostMessageScheduler(_MicrotaskCallback callback): super(callback) {
// Messages from other windows do not cause a security risk as
@@ -33921,77 +33974,6 @@
return allowsElement(element);
}
}
-// 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.
-
-
-/**
- * A utility class for representing two-dimensional positions.
- */
-class Point {
- final num x;
- final num y;
-
- const Point([num x = 0, num y = 0]): x = x, y = y;
-
- String toString() => '($x, $y)';
-
- bool operator ==(other) {
- if (other is !Point) return false;
- return x == other.x && y == other.y;
- }
-
- int get hashCode => JenkinsSmiHash.hash2(x.hashCode, y.hashCode);
-
- Point operator +(Point other) {
- return new Point(x + other.x, y + other.y);
- }
-
- Point operator -(Point other) {
- return new Point(x - other.x, y - other.y);
- }
-
- Point operator *(num factor) {
- return new Point(x * factor, y * factor);
- }
-
- /**
- * Get the straight line (Euclidean) distance between the origin (0, 0) and
- * this point.
- */
- num get magnitude => sqrt(x * x + y * y);
-
- /**
- * Returns the distance between two points.
- */
- double distanceTo(Point other) {
- var dx = x - other.x;
- var dy = y - other.y;
- return sqrt(dx * dx + dy * dy);
- }
-
- /**
- * Returns the squared distance between two points.
- *
- * Squared distances can be used for comparisons when the actual value is not
- * required.
- */
- num squaredDistanceTo(Point other) {
- var dx = x - other.x;
- var dy = y - other.y;
- return dx * dx + dy * dy;
- }
-
- Point ceil() => new Point(x.ceil(), y.ceil());
- Point floor() => new Point(x.floor(), y.floor());
- Point round() => new Point(x.round(), y.round());
-
- /**
- * Truncates x and y to integers and returns the result as a new point.
- */
- Point toInt() => new Point(x.toInt(), y.toInt());
-}
// Copyright (c) 2011, 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.
@@ -34017,163 +33999,6 @@
*/
static const String COMPLETE = "complete";
}
-// 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.
-
-
-/**
- * A base class for representing two-dimensional rectangles. This will hopefully
- * be moved merged with the dart:math Rect.
- */
-// TODO(efortuna): Merge with Math rect after finalizing with Florian.
-abstract class RectBase {
- // Not used, but keeps the VM from complaining about Rect having a const
- // constructor and this one not.
- const RectBase();
-
- num get left;
- num get top;
- num get width;
- num get height;
-
- num get right => left + width;
- num get bottom => top + height;
-
- // NOTE! All code below should be common with Rect.
-
- String toString() {
- return '($left, $top, $width, $height)';
- }
-
- bool operator ==(other) {
- if (other is !Rect) return false;
- return left == other.left && top == other.top && width == other.width &&
- height == other.height;
- }
-
- int get hashCode => JenkinsSmiHash.hash4(left.hashCode, top.hashCode,
- width.hashCode, height.hashCode);
-
- /**
- * Computes the intersection of this rectangle and the rectangle parameter.
- * Returns null if there is no intersection.
- */
- Rect intersection(Rect rect) {
- var x0 = max(left, rect.left);
- var x1 = min(left + width, rect.left + rect.width);
-
- if (x0 <= x1) {
- var y0 = max(top, rect.top);
- var y1 = min(top + height, rect.top + rect.height);
-
- if (y0 <= y1) {
- return new Rect(x0, y0, x1 - x0, y1 - y0);
- }
- }
- return null;
- }
-
-
- /**
- * Returns whether a rectangle intersects this rectangle.
- */
- bool intersects(Rect other) {
- return (left <= other.left + other.width && other.left <= left + width &&
- top <= other.top + other.height && other.top <= top + height);
- }
-
- /**
- * Returns a new rectangle which completely contains this rectangle and the
- * input rectangle.
- */
- Rect union(Rect rect) {
- var right = max(this.left + this.width, rect.left + rect.width);
- var bottom = max(this.top + this.height, rect.top + rect.height);
-
- var left = min(this.left, rect.left);
- var top = min(this.top, rect.top);
-
- return new Rect(left, top, right - left, bottom - top);
- }
-
- /**
- * Tests whether this rectangle entirely contains another rectangle.
- */
- bool containsRect(Rect another) {
- return left <= another.left &&
- left + width >= another.left + another.width &&
- top <= another.top &&
- top + height >= another.top + another.height;
- }
-
- /**
- * Tests whether this rectangle entirely contains a point.
- */
- bool containsPoint(Point another) {
- return another.x >= left &&
- another.x <= left + width &&
- another.y >= top &&
- another.y <= top + height;
- }
-
- Rect ceil() => new Rect(left.ceil(), top.ceil(), width.ceil(), height.ceil());
- Rect floor() => new Rect(left.floor(), top.floor(), width.floor(),
- height.floor());
- Rect round() => new Rect(left.round(), top.round(), width.round(),
- height.round());
-
- /**
- * Truncates coordinates to integers and returns the result as a new
- * rectangle.
- */
- Rect toInt() => new Rect(left.toInt(), top.toInt(), width.toInt(),
- height.toInt());
-
- Point get topLeft => new Point(this.left, this.top);
- Point get bottomRight => new Point(this.left + this.width,
- this.top + this.height);
-}
-
-
-
-/**
- * A class for representing two-dimensional rectangles.
- *
- * This class is distinctive from RectBase in that it enforces that its
- * properties are immutable.
- */
-class Rect extends RectBase {
- final num left;
- final num top;
- final num width;
- final num height;
-
- const Rect(this.left, this.top, this.width, this.height): super();
-
- factory Rect.fromPoints(Point a, Point b) {
- var left;
- var width;
- if (a.x < b.x) {
- left = a.x;
- width = b.x - left;
- } else {
- left = b.x;
- width = a.x - left;
- }
- var top;
- var height;
- if (a.y < b.y) {
- top = a.y;
- height = b.y - top;
- } else {
- top = b.y;
- height = a.y - top;
- }
-
- return new Rect(left, top, width, height);
- }
-}
// 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.
@@ -35022,7 +34847,6 @@
static window() native "Utils_window";
static forwardingPrint(String message) native "Utils_forwardingPrint";
- static void spawnDomFunction(Function f, int replyTo) native "Utils_spawnDomFunction";
static int _getNewIsolateId() native "Utils_getNewIsolateId";
// The following methods were added for debugger integration to make working
@@ -35056,6 +34880,15 @@
}
static _ConsoleVariables _consoleTempVariables = new _ConsoleVariables();
+
+ /**
+ * Header passed in from the Dartium Developer Tools when an expression is
+ * evaluated in the console as opposed to the watch window or another context
+ * that does not expect REPL support.
+ */
+ static const _CONSOLE_API_SUPPORT_HEADER =
+ 'with ((this && this.console && this.console._commandLineAPI) || {}) {\n';
+
/**
* Takes an [expression] and a list of [local] variable and returns an
* expression for a closure with a body matching the original expression
@@ -35066,11 +34899,22 @@
* with the list of arguments passed to this method.
*
* For example:
- * <code>wrapExpressionAsClosure("foo + bar", ["bar", 40, "foo", 2])</code>
+ * <code>
+ * _consoleTempVariables = {'a' : someValue, 'b': someOtherValue}
+ * wrapExpressionAsClosure("${_CONSOLE_API_SUPPORT_HEADER}foo + bar + a",
+ * ["bar", 40, "foo", 2])
+ * </code>
* will return:
- * <code>["(final $var, final bar, final foo) => foo + bar", [40, 2]]</code>
+ * <code>
+ * ["""(final $consoleVariables, final bar, final foo, final a, final b) =>
+ * (foo + bar + a
+ * )""",
+ * [_consoleTempVariables, 40, 2, someValue, someOtherValue]]
+ * </code>
*/
static List wrapExpressionAsClosure(String expression, List locals) {
+ // FIXME: dartbug.com/10434 find a less fragile way to determine whether
+ // we need to strip off console API support added by InjectedScript.
var args = {};
var sb = new StringBuffer("(");
addArg(arg, value) {
@@ -35089,16 +34933,111 @@
args[arg] = value;
}
- addArg("\$var", _consoleTempVariables);
+ if (expression.indexOf(_CONSOLE_API_SUPPORT_HEADER) == 0) {
+ expression = expression.substring(expression.indexOf('\n') + 1);
+ expression = expression.substring(0, expression.lastIndexOf('\n'));
- for (int i = 0; i < locals.length; i+= 2) {
- addArg(locals[i], locals[i+1]);
+ addArg("\$consoleVariables", _consoleTempVariables);
+
+ // FIXME: use a real Dart tokenizer. The following regular expressions
+ // only allow setting variables at the immediate start of the expression
+ // to limit the number of edge cases we have to handle.
+
+ // Match expressions that start with "var x"
+ final _VARIABLE_DECLARATION = new RegExp("^(\\s*)var\\s+(\\w+)");
+ // Match expressions that start with "someExistingConsoleVar ="
+ final _SET_VARIABLE = new RegExp("^(\\s*)(\\w+)(\\s*=)");
+ // Match trailing semicolons.
+ final _ENDING_SEMICOLONS = new RegExp("(;\\s*)*\$");
+ expression = expression.replaceAllMapped(_VARIABLE_DECLARATION,
+ (match) {
+ var variableName = match[2];
+ // Set the console variable if it isn't already set.
+ if (!_consoleTempVariables._data.containsKey(variableName)) {
+ _consoleTempVariables._data[variableName] = null;
+ }
+ return "${match[1]}\$consoleVariables.${variableName}";
+ });
+
+ expression = expression.replaceAllMapped(_SET_VARIABLE,
+ (match) {
+ var variableName = match[2];
+ // Only rewrite if the name matches an existing console variable.
+ if (_consoleTempVariables._data.containsKey(variableName)) {
+ return "${match[1]}\$consoleVariables.${variableName}${match[3]}";
+ } else {
+ return match[0];
+ }
+ });
+
+ // We only allow dart expressions not Dart statements. Silently remove
+ // trailing semicolons the user might have added by accident to reduce the
+ // number of spurious compile errors.
+ expression = expression.replaceFirst(_ENDING_SEMICOLONS, "");
}
- sb..write(')=>\n$expression');
+
+ if (locals != null) {
+ for (int i = 0; i < locals.length; i+= 2) {
+ addArg(locals[i], locals[i+1]);
+ }
+ }
+ // Inject all the already defined console variables.
+ _consoleTempVariables._data.forEach(addArg);
+
+ // TODO(jacobr): remove the parentheses around the expresson once
+ // dartbug.com/13723 is fixed. Currently we wrap expression in parentheses
+ // to ensure only valid Dart expressions are allowed. Otherwise the DartVM
+ // quietly ignores trailing Dart statements resulting in user confusion
+ // when part of an invalid expression they entered is ignored.
+ sb..write(') => (\n$expression\n)');
return [sb.toString(), args.values.toList(growable: false)];
}
/**
+ * TODO(jacobr): this is a big hack to get around the fact that we are still
+ * passing some JS expression to the evaluate method even when in a Dart
+ * context.
+ */
+ static bool isJsExpression(String expression) =>
+ expression.startsWith("(function getCompletions");
+
+ /**
+ * Returns a list of completions to use if the receiver is o.
+ */
+ static List<String> getCompletions(o) {
+ MirrorSystem system = currentMirrorSystem();
+ var completions = new Set<String>();
+ addAll(Map<Symbol, dynamic> map, bool isStatic) {
+ map.forEach((symbol, mirror) {
+ if (mirror.isStatic == isStatic && !mirror.isPrivate) {
+ var name = MirrorSystem.getName(symbol);
+ if (mirror is MethodMirror && mirror.isSetter)
+ name = name.substring(0, name.length - 1);
+ completions.add(name);
+ }
+ });
+ }
+
+ addForClass(ClassMirror mirror, bool isStatic) {
+ if (mirror == null)
+ return;
+ addAll(mirror.members, isStatic);
+ if (mirror.superclass != null)
+ addForClass(mirror.superclass, isStatic);
+ for (var interface in mirror.superinterfaces) {
+ addForClass(interface, isStatic);
+ }
+ }
+
+ if (o is Type) {
+ addForClass(reflectClass(o), true);
+ } else {
+ addForClass(reflect(o).type, false);
+ }
+ return completions.toList(growable: false);
+ }
+
+ /**
* Convenience helper to get the keys of a [Map] as a [List].
*/
static List getMapKeyList(Map map) => map.keys.toList();
@@ -35281,79 +35220,10 @@
bool get isNotEmpty => Maps.isNotEmpty(this);
}
-// TODO(vsm): Remove DOM isolate code. This is only used to support
-// printing and timers in background isolates. Background isolates
-// should just forward to the main DOM isolate instead of requiring a
-// special DOM isolate.
-
-_makeSendPortFuture(spawnRequest) {
- final completer = new Completer<SendPort>.sync();
- final port = new ReceivePort();
- port.receive((result, _) {
- completer.complete(result);
- port.close();
- });
- // TODO: SendPort.hashCode is ugly way to access port id.
- spawnRequest(port.toSendPort().hashCode);
- return completer.future;
-}
-
-Future<SendPort> _spawnDomFunction(Function f) =>
- _makeSendPortFuture((portId) { _Utils.spawnDomFunction(f, portId); });
-
-final Future<SendPort> __HELPER_ISOLATE_PORT =
- _spawnDomFunction(_helperIsolateMain);
-
-// Tricky part.
-// Once __HELPER_ISOLATE_PORT gets resolved, it will still delay in .then
-// and to delay Timer.run is used. However, Timer.run will try to register
-// another Timer and here we got stuck: event cannot be posted as then
-// callback is not executed because it's delayed with timer.
-// Therefore once future is resolved, it's unsafe to call .then on it
-// in Timer code.
-SendPort __SEND_PORT;
-
-_sendToHelperIsolate(msg, SendPort replyTo) {
- if (__SEND_PORT != null) {
- __SEND_PORT.send(msg, replyTo);
- } else {
- __HELPER_ISOLATE_PORT.then((port) {
- __SEND_PORT = port;
- __SEND_PORT.send(msg, replyTo);
- });
- }
-}
-
-final _TIMER_REGISTRY = new Map<SendPort, Timer>();
-
-const _NEW_TIMER = 'NEW_TIMER';
-const _CANCEL_TIMER = 'CANCEL_TIMER';
-const _TIMER_PING = 'TIMER_PING';
-const _PRINT = 'PRINT';
-
-_helperIsolateMain() {
- port.receive((msg, replyTo) {
- final cmd = msg[0];
- if (cmd == _NEW_TIMER) {
- final duration = new Duration(milliseconds: msg[1]);
- bool periodic = msg[2];
- ping() { replyTo.send(_TIMER_PING); };
- _TIMER_REGISTRY[replyTo] = periodic ?
- new Timer.periodic(duration, (_) { ping(); }) :
- new Timer(duration, ping);
- } else if (cmd == _CANCEL_TIMER) {
- _TIMER_REGISTRY.remove(replyTo).cancel();
- } else if (cmd == _PRINT) {
- final message = msg[1];
- // TODO(antonm): we need somehow identify those isolates.
- print('[From isolate] $message');
- }
- });
-}
-
final _printClosure = window.console.log;
final _pureIsolatePrintClosure = (s) {
- _sendToHelperIsolate([_PRINT, s], null);
+ throw new UnimplementedError("Printing from a background isolate "
+ "is not supported in the browser");
};
final _forwardingPrintClosure = _Utils.forwardingPrint;
@@ -35392,46 +35262,10 @@
return new _Timer(milliSeconds, callback, repeating);
};
-
-class _PureIsolateTimer implements Timer {
- bool _isActive = true;
- final ReceivePort _port = new ReceivePort();
- SendPort _sendPort; // Effectively final.
-
- static SendPort _SEND_PORT;
-
- _PureIsolateTimer(int milliSeconds, callback, repeating) {
- _sendPort = _port.toSendPort();
- _port.receive((msg, replyTo) {
- assert(msg == _TIMER_PING);
- _isActive = repeating;
- callback(this);
- if (!repeating) _cancel();
- });
-
- _send([_NEW_TIMER, milliSeconds, repeating]);
- }
-
- void cancel() {
- _cancel();
- _send([_CANCEL_TIMER]);
- }
-
- void _cancel() {
- _isActive = false;
- _port.close();
- }
-
- _send(msg) {
- _sendToHelperIsolate(msg, _sendPort);
- }
-
- bool get isActive => _isActive;
-}
-
get _pureIsolateTimerFactoryClosure =>
((int milliSeconds, void callback(Timer time), bool repeating) =>
- new _PureIsolateTimer(milliSeconds, callback, repeating));
+ throw new UnimplementedError("Timers on background isolates "
+ "are not supported in the browser"));
void _initializeCustomElement(Element e) {
_Utils.initializeCustomElement(e);
diff --git a/sdk/lib/html/html_common/html_common.dart b/sdk/lib/html/html_common/html_common.dart
index 1944bd4..72d5dab 100644
--- a/sdk/lib/html/html_common/html_common.dart
+++ b/sdk/lib/html/html_common/html_common.dart
@@ -13,7 +13,6 @@
part 'css_class_set.dart';
part 'device.dart';
part 'filtered_element_list.dart';
-part 'jenkins_smi_hash.dart';
part 'lists.dart';
// For annotating deprecated APIs.
diff --git a/sdk/lib/html/html_common/html_common_dart2js.dart b/sdk/lib/html/html_common/html_common_dart2js.dart
index c7b7ea1..3afd514 100644
--- a/sdk/lib/html/html_common/html_common_dart2js.dart
+++ b/sdk/lib/html/html_common/html_common_dart2js.dart
@@ -18,7 +18,6 @@
part 'conversions.dart';
part 'device.dart';
part 'filtered_element_list.dart';
-part 'jenkins_smi_hash.dart';
part 'lists.dart';
// For annotating deprecated APIs.
diff --git a/sdk/lib/io/directory.dart b/sdk/lib/io/directory.dart
index 6aa18f8..80391d4 100644
--- a/sdk/lib/io/directory.dart
+++ b/sdk/lib/io/directory.dart
@@ -68,59 +68,45 @@
void createSync({bool recursive: false});
/**
- * Creates a temporary directory in this directory. Additional random
- * characters are appended to [template] to produce a unique directory
- * name.
+ * Gets the system temp directory.
+ *
+ * Gets the directory provided by the operating system for creating
+ * temporary files and directories in.
+ * The location of the system temp directory is platform-dependent,
+ * and may be set by an environment variable.
+ */
+ static Directory get systemTemp => _Directory.systemTemp;
+
+ /**
+ * Creates a temporary directory in this directory. Additional random
+ * characters are appended to [prefix] to produce a unique directory
+ * name. If [prefix] is missing or null, the empty string is used
+ * for [prefix].
*
* Returns a [:Future<Directory>:] that completes with the newly
* created temporary directory.
*
* Deprecated behavior, to be removed Oct 18, 2013: If the path is the
* empty string, the directory is created in the default system temp
- * directory. This capability has been moved to the static function
- * [createSystemTemp].
+ * directory. This capability has been moved to the static getter
+ * [systemTemp].
*/
Future<Directory> createTemp([String template]);
/**
* Synchronously creates a temporary directory in this directory.
- * Additional random characters are appended to [template] to produce
- * a unique directory name.
+ * Additional random characters are appended to [prefix] to produce
+ * a unique directory name. If [prefix] is missing or null, the empty
+ * string is used for [prefix].
*
* Returns the newly created temporary directory.
*
* Deprecated behavior, to be removed Oct 18, 2013: If the path is the
* empty string, the directory is created in the default system temp
- * directory. This capability has been moved to the static function
+ * directory. This capability has been moved to the static function
* [createSystemTemp].
*/
- Directory createTempSync([String template]);
-
- /**
- * Creates a temporary directory in the system temp directory.
- * The location of the system temp directory is platform-dependent,
- * and may be set by an environment variable.
- * Additional random characters are appended to [template] to produce
- * a unique directory name.
- *
- * Returns a [:Future<Directory>:] that completes with the newly
- * created temporary directory.
- */
- static Future<Directory> createSystemTemp([String template]) =>
- _Directory.createSystemTemp(template);
-
- /**
- * Synchronously creates a temporary directory in the system temp directory.
- * The location of the system temp directory is platform-dependent,
- * and may be set by an environment variable.
- * Additional random characters are appended to [template] to produce
- * a unique directory name.
- *
- * Returns a [:Future<Directory>:] that completes with the newly
- * created temporary directory.
- */
- static Directory createSystemTempSync([String template]) =>
- _Directory.createSystemTempSync(template);
+ Directory createTempSync([String template]);
Future<String> resolveSymbolicLinks();
diff --git a/sdk/lib/io/directory_impl.dart b/sdk/lib/io/directory_impl.dart
index ac048de..2883648 100644
--- a/sdk/lib/io/directory_impl.dart
+++ b/sdk/lib/io/directory_impl.dart
@@ -16,7 +16,8 @@
external static _current();
external static _setCurrent(path);
- external static _createTemp(String template, bool system);
+ external static _createTemp(String path);
+ external static String _systemTemp();
external static int _exists(String path);
external static _create(String path);
external static _deleteNative(String path, bool recursive);
@@ -149,17 +150,22 @@
}
}
- // TODO(13720): Make template argument mandatory on Oct 18, 2013.
- Future<Directory> createTemp([String template]) {
+ static Directory get systemTemp => new Directory(_systemTemp());
+
+ Future<Directory> createTemp([String prefix]) {
+ if (prefix == null) prefix = '';
if (path == '') {
- if (template == null) template = '';
- return createSystemTemp(template);
+ return systemTemp.createTemp(prefix);
// TODO(13720): On Oct 18, 2013, replace this with
// an error. createTemp cannot be called on a Directory with empty path.
}
- String fullTemplate = "$path${Platform.pathSeparator}";
- if (template != null) fullTemplate = "$fullTemplate$template";
- return _IOService.dispatch(_DIRECTORY_CREATE_TEMP, [fullTemplate])
+ String fullPrefix;
+ if (path.endsWith('/') || (Platform.isWindows && path.endsWith('\\'))) {
+ fullPrefix = "$path$prefix";
+ } else {
+ fullPrefix = "$path${Platform.pathSeparator}$prefix";
+ }
+ return _IOService.dispatch(_DIRECTORY_CREATE_TEMP, [fullPrefix])
.then((response) {
if (_isErrorResponse(response)) {
throw _exceptionOrErrorFromResponse(
@@ -169,41 +175,23 @@
});
}
- // TODO(13720): Make template argument mandatory on Oct 18, 2013.
- Directory createTempSync([String template]) {
+ Directory createTempSync([String prefix]) {
+ if (prefix == null) prefix = '';
if (path == '') {
- if (template == null) template = '';
- return createSystemTempSync(template);
+ return systemTemp.createTempSync(prefix);
// TODO(13720): On Oct 18, 2013, replace this with
// an error. createTemp cannot be called on a Directory with empty path.
}
- String fullTemplate = "$path${Platform.pathSeparator}";
- if (template != null) fullTemplate = "$fullTemplate$template";
- var result = _createTemp(fullTemplate, false);
- if (result is OSError) {
- throw new DirectoryException("Creation of temporary directory failed",
- fullTemplate,
- result);
+ String fullPrefix;
+ if (path.endsWith('/') || (Platform.isWindows && path.endsWith('\\'))) {
+ fullPrefix = "$path$prefix";
+ } else {
+ fullPrefix = "$path${Platform.pathSeparator}$prefix";
}
- return new Directory(result);
- }
-
- static Future<Directory> createSystemTemp(String template) {
- return _IOService.dispatch(_DIRECTORY_CREATE_SYSTEM_TEMP,
- [template]).then((response) {
- if (response is List && response[0] != _SUCCESS_RESPONSE) {
- throw new _Directory(template)._exceptionOrErrorFromResponse(
- response, "Creation of temporary directory failed");
- }
- return new Directory(response);
- });
- }
-
- static Directory createSystemTempSync(String template) {
- var result = _createTemp(template, true);
+ var result = _createTemp(fullPrefix);
if (result is OSError) {
throw new DirectoryException("Creation of temporary directory failed",
- template,
+ fullPrefix,
result);
}
return new Directory(result);
diff --git a/sdk/lib/io/http_impl.dart b/sdk/lib/io/http_impl.dart
index fcaf191..312bb1c 100644
--- a/sdk/lib/io/http_impl.dart
+++ b/sdk/lib/io/http_impl.dart
@@ -1568,38 +1568,10 @@
Future<HttpClientRequest> _openUrlFromRequest(String method,
Uri uri,
_HttpClientRequest previous) {
- var u = uri;
// If the new URI is relative (to either '/' or some sub-path),
// construct a full URI from the previous one.
- // See http://tools.ietf.org/html/rfc3986#section-4.2
- replaceComponents({scheme, host, port, path}) {
- uri = new Uri(
- scheme: scheme != null ? scheme : uri.scheme,
- host: host != null ? host : uri.host,
- port: port != null ? port : uri.port,
- path: path != null ? path : uri.path,
- query: uri.query,
- fragment: uri.fragment);
- }
-
- var scheme;
- var host;
- var port;
- var path;
- if (uri.host.isEmpty) {
- host = previous.uri.host;
- port = previous.uri.port;
- }
- if (uri.scheme.isEmpty) {
- scheme = previous.uri.scheme;
- }
- if (!uri.path.startsWith('/')) {
- var absolute = new _Path.raw(previous.uri.path).directoryPath;
- absolute = absolute.join(new _Path.raw(u.path));
- path = absolute.canonicalize().toString();
- }
- replaceComponents(scheme: scheme, host: host, port: port, path: path);
- return openUrl(method, uri).then((_HttpClientRequest request) {
+ Uri resolved = previous.uri.resolveUri(uri);
+ return openUrl(method, resolved).then((_HttpClientRequest request) {
// Only follow redirects if initial request did.
request.followRedirects = previous.followRedirects;
// Allow same number of redirects.
diff --git a/sdk/lib/io/io_service.dart b/sdk/lib/io/io_service.dart
index 037cdd1..bf4b42b 100644
--- a/sdk/lib/io/io_service.dart
+++ b/sdk/lib/io/io_service.dart
@@ -38,12 +38,11 @@
const int _DIRECTORY_DELETE = 30;
const int _DIRECTORY_EXISTS = 31;
const int _DIRECTORY_CREATE_TEMP = 32;
-const int _DIRECTORY_CREATE_SYSTEM_TEMP = 33;
-const int _DIRECTORY_LIST_START = 34;
-const int _DIRECTORY_LIST_NEXT = 35;
-const int _DIRECTORY_LIST_STOP = 36;
-const int _DIRECTORY_RENAME = 37;
-const int _SSL_PROCESS_FILTER = 38;
+const int _DIRECTORY_LIST_START = 33;
+const int _DIRECTORY_LIST_NEXT = 34;
+const int _DIRECTORY_LIST_STOP = 35;
+const int _DIRECTORY_RENAME = 36;
+const int _SSL_PROCESS_FILTER = 37;
class _IOService {
external static Future dispatch(int request, List data);
diff --git a/sdk/lib/json/json.dart b/sdk/lib/json/json.dart
index 8bd8ab2..114feea 100644
--- a/sdk/lib/json/json.dart
+++ b/sdk/lib/json/json.dart
@@ -6,14 +6,18 @@
* Utilities for encoding and decoding JSON (JavaScript Object Notation) data.
*/
+@deprecated
library dart.json;
import "dart:convert";
+import "dart:_collection-dev" show deprecated;
export "dart:convert" show JsonUnsupportedObjectError, JsonCyclicError;
// JSON parsing and serialization.
/**
+ * *DEPRECATED* Use `dart:convert JSON.decode` instead.
+ *
* Parses [json] and build the corresponding parsed JSON value.
*
* Parsed JSON values are of the types [num], [String], [bool], [Null],
@@ -28,6 +32,7 @@
*
* Throws [FormatException] if the input is not valid JSON text.
*/
+@deprecated
parse(String json, [reviver(var key, var value)]) {
if (reviver != null) {
var original = reviver;
@@ -37,6 +42,8 @@
}
/**
+ * *DEPRECATED* Use `dart:convert JSON.encode` instead.
+ *
* Serializes [object] into a JSON string.
*
* Directly serializable values are [num], [String], [bool], and [Null], as well
@@ -63,11 +70,14 @@
* the JSON text for it. I.e., if an object changes after it is first
* serialized, the new values may or may not be reflected in the result.
*/
+@deprecated
String stringify(Object object) {
return _JsonStringifier.stringify(object);
}
/**
+ * *DEPRECATED* Use `package:json/json.dart` or `dart:convert` instead.
+ *
* Serializes [object] into [output] stream.
*
* Performs the same operations as [stringify] but outputs the resulting
@@ -76,6 +86,7 @@
* If serialization fails by throwing, some data might have been added to
* [output], but it won't contain valid JSON text.
*/
+@deprecated
void printOn(Object object, StringSink output) {
return _JsonStringifier.printOn(object, output);
}
@@ -84,6 +95,8 @@
// Simple API for JSON parsing.
+/// *DEPRECATED* Use `package:json/json.dart` instead.
+@deprecated
abstract class JsonListener {
void handleString(String value) {}
void handleNumber(num value) {}
@@ -101,11 +114,14 @@
}
/**
+ * *DEPRECATED* Use `package:json/json.dart` instead.
+ *
* A [JsonListener] that builds data objects from the parser events.
*
* This is a simple stack-based object builder. It keeps the most recently
* seen value in a variable, and uses it depending on the following event.
*/
+@deprecated
class BuildJsonListener extends JsonListener {
/**
* Stack used to handle nested containers.
@@ -184,6 +200,8 @@
typedef _Reviver(var key, var value);
+/// *DEPRECATED* Use `package:json/json.dart` instead.
+@deprecated
class ReviverJsonListener extends BuildJsonListener {
final _Reviver reviver;
ReviverJsonListener(reviver(key, value)) : this.reviver = reviver;
@@ -204,6 +222,8 @@
}
}
+/// *DEPRECATED* Use `package:json/json.dart` instead.
+@deprecated
class JsonParser {
// A simple non-recursive state-based parser for JSON.
//
diff --git a/sdk/lib/html/html_common/jenkins_smi_hash.dart b/sdk/lib/math/jenkins_smi_hash.dart
similarity index 90%
rename from sdk/lib/html/html_common/jenkins_smi_hash.dart
rename to sdk/lib/math/jenkins_smi_hash.dart
index 7938e50..8a0056e 100644
--- a/sdk/lib/html/html_common/jenkins_smi_hash.dart
+++ b/sdk/lib/math/jenkins_smi_hash.dart
@@ -1,8 +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.
-
-part of html_common;
+part of dart.math;
/**
* This is the [Jenkins hash function][1] but using masking to keep
@@ -20,8 +19,8 @@
* }
* hash = JenkinsSmiHash.finish(hash);
*/
-class JenkinsSmiHash {
- // TODO: Bug 11617- This class should be optimized and standardized elsewhere.
+class _JenkinsSmiHash {
+ // TODO(11617): This class should be optimized and standardized elsewhere.
static int combine(int hash, int value) {
hash = 0x1fffffff & (hash + value);
diff --git a/sdk/lib/math/math.dart b/sdk/lib/math/math.dart
index 4cffa8f..95ed261 100644
--- a/sdk/lib/math/math.dart
+++ b/sdk/lib/math/math.dart
@@ -7,7 +7,10 @@
*/
library dart.math;
+part "jenkins_smi_hash.dart";
+part "point.dart";
part "random.dart";
+part "rectangle.dart";
/**
* Base of the natural logarithms.
diff --git a/sdk/lib/math/math_sources.gypi b/sdk/lib/math/math_sources.gypi
index ed2577e..c26d41c 100644
--- a/sdk/lib/math/math_sources.gypi
+++ b/sdk/lib/math/math_sources.gypi
@@ -6,6 +6,9 @@
'sources': [
'math.dart',
# The above file needs to be first as it lists the parts below.
+ 'jenkins_smi_hash.dart',
+ 'point.dart',
'random.dart',
+ 'rectangle.dart',
],
}
diff --git a/sdk/lib/math/point.dart b/sdk/lib/math/point.dart
new file mode 100644
index 0000000..37411b7
--- /dev/null
+++ b/sdk/lib/math/point.dart
@@ -0,0 +1,81 @@
+// 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 dart.math;
+
+/**
+ * A utility class for representing two-dimensional positions.
+ */
+class Point<T extends num> {
+ final T x;
+ final T y;
+
+ const Point([T x = 0, T y = 0]): this.x = x, this.y = y;
+
+ String toString() => 'Point($x, $y)';
+
+ bool operator ==(other) {
+ if (other is !Point) return false;
+ return x == other.x && y == other.y;
+ }
+
+ int get hashCode => _JenkinsSmiHash.hash2(x.hashCode, y.hashCode);
+
+ /**
+ * Add [other] to `this`, as if both points were vectors.
+ *
+ * Returns the resulting "vector" as a Point.
+ */
+ Point<T> operator +(Point<T> other) {
+ return new Point<T>(x + other.x, y + other.y);
+ }
+
+ /**
+ * Subtract [other] from `this`, as if both points were vectors.
+ *
+ * Returns the resulting "vector" as a Point.
+ */
+ Point<T> operator -(Point<T> other) {
+ return new Point<T>(x - other.x, y - other.y);
+ }
+
+ /**
+ * Scale this point by [factor] as if it were a vector.
+ *
+ * *Important* *Note*: This function accepts a `num` as its argument only so
+ * that you can scale Point<double> objects by an `int` factor. Because the
+ * star operator always returns the same type of Point that originally called
+ * it, passing in a double [factor] on a `Point<int>` _causes_ _a_
+ * _runtime_ _error_ in checked mode.
+ */
+ Point<T> operator *(num factor) {
+ return new Point<T>(x * factor, y * factor);
+ }
+
+ /**
+ * Get the straight line (Euclidean) distance between the origin (0, 0) and
+ * this point.
+ */
+ double get magnitude => sqrt(x * x + y * y);
+
+ /**
+ * Returns the distance between `this` and [other].
+ */
+ double distanceTo(Point<T> other) {
+ var dx = x - other.x;
+ var dy = y - other.y;
+ return sqrt(dx * dx + dy * dy);
+ }
+
+ /**
+ * Returns the squared distance between `this` and [other].
+ *
+ * Squared distances can be used for comparisons when the actual value is not
+ * required.
+ */
+ T squaredDistanceTo(Point<T> other) {
+ var dx = x - other.x;
+ var dy = y - other.y;
+ return dx * dx + dy * dy;
+ }
+}
diff --git a/sdk/lib/math/rectangle.dart b/sdk/lib/math/rectangle.dart
new file mode 100644
index 0000000..763a251
--- /dev/null
+++ b/sdk/lib/math/rectangle.dart
@@ -0,0 +1,157 @@
+// 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 dart.math;
+
+/**
+ * A base class for representing two-dimensional axis-aligned rectangles.
+ */
+abstract class _RectangleBase<T extends num> {
+ const _RectangleBase();
+
+ /** The x-coordinate of the left edge. */
+ T get left;
+ /** The y-coordinate of the top edge. */
+ T get top;
+ /** The `width` of the rectangle. */
+ T get width;
+ /** The `height` of the rectangle. */
+ T get height;
+
+ /** The x-coordinate of the right edge. */
+ T get right => left + width;
+ /** The y-coordinate of the bottom edge. */
+ T get bottom => top + height;
+
+ String toString() {
+ return 'Rectangle ($left, $top) $width x $height';
+ }
+
+ bool operator ==(other) {
+ if (other is !Rectangle) return false;
+ return left == other.left && top == other.top && width == other.width &&
+ height == other.height;
+ }
+
+ int get hashCode => _JenkinsSmiHash.hash4(left.hashCode, top.hashCode,
+ width.hashCode, height.hashCode);
+
+ /**
+ * Computes the intersection of `this` and [other].
+ *
+ * The intersection of two axis-aligned rectangles, if any, is always another
+ * axis-aligned rectangle.
+ *
+ * Returns the intersection of this and `other`, or `null` if they don't
+ * intersect.
+ */
+ Rectangle<T> intersection(Rectangle<T> other) {
+ var x0 = max(left, other.left);
+ var x1 = min(left + width, other.left + other.width);
+
+ if (x0 <= x1) {
+ var y0 = max(top, other.top);
+ var y1 = min(top + height, other.top + other.height);
+
+ if (y0 <= y1) {
+ return new Rectangle<T>(x0, y0, x1 - x0, y1 - y0);
+ }
+ }
+ return null;
+ }
+
+
+ /**
+ * Returns true if `this` intersects [other].
+ */
+ bool intersects(Rectangle<num> other) {
+ return (left <= other.left + other.width &&
+ other.left <= left + width &&
+ top <= other.top + other.height &&
+ other.top <= top + height);
+ }
+
+ /**
+ * Returns a new rectangle which completely contains `this` and [other].
+ */
+ Rectangle<T> boundingBox(Rectangle<T> other) {
+ var right = max(this.left + this.width, other.left + other.width);
+ var bottom = max(this.top + this.height, other.top + other.height);
+
+ var left = min(this.left, other.left);
+ var top = min(this.top, other.top);
+
+ return new Rectangle<T>(left, top, right - left, bottom - top);
+ }
+
+ /**
+ * Tests whether `this` entirely contains [another].
+ */
+ bool contains(Rectangle<num> another) {
+ return left <= another.left &&
+ left + width >= another.left + another.width &&
+ top <= another.top &&
+ top + height >= another.top + another.height;
+ }
+
+ /**
+ * Tests whether [another] is inside or along the edges of `this`.
+ */
+ bool containsPoint(Point<num> another) {
+ return another.x >= left &&
+ another.x <= left + width &&
+ another.y >= top &&
+ another.y <= top + height;
+ }
+
+ Point<T> get topLeft => new Point<T>(this.left, this.top);
+ Point<T> get topRight => new Point<T>(this.left + this.width, this.top);
+ Point<T> get bottomRight => new Point<T>(this.left + this.width,
+ this.top + this.height);
+ Point<T> get bottomLeft => new Point<T>(this.left,
+ this.top + this.height);
+}
+
+
+/**
+ * A class for representing two-dimensional rectangles whose properties are
+ * immutable.
+ */
+class Rectangle<T extends num> extends _RectangleBase<T> {
+ final T left;
+ final T top;
+ final T width;
+ final T height;
+
+ const Rectangle(this.left, this.top, this.width, this.height);
+
+ factory Rectangle.fromPoints(Point<T> a, Point<T> b) {
+ T left = min(a.x, b.x);
+ T width = max(a.x, b.x) - left;
+ T top = min(a.y, b.y);
+ T height = max(a.y, b.y) - top;
+ return new Rectangle<T>(left, top, width, height);
+ }
+}
+
+/**
+ * A class for representing two-dimensional axis-aligned rectangles with mutable
+ * properties.
+ */
+class MutableRectangle<T extends num> extends _RectangleBase<T>
+ implements Rectangle<T> {
+ T left;
+ T top;
+ T width;
+ T height;
+
+ MutableRectangle(this.left, this.top, this.width, this.height);
+
+ factory MutableRectangle.fromPoints(Point<T> a, Point<T> b) {
+ T left = min(a.x, b.x);
+ T width = max(a.x, b.x) - left;
+ T top = min(a.y, b.y);
+ T height = max(a.y, b.y) - top;
+ return new MutableRectangle<T>(left, top, width, height);
+ }
+}
diff --git a/sdk/lib/utf/utf.dart b/sdk/lib/utf/utf.dart
index 43a2944..229b5aa 100644
--- a/sdk/lib/utf/utf.dart
+++ b/sdk/lib/utf/utf.dart
@@ -3,10 +3,12 @@
// BSD-style license that can be found in the LICENSE file.
/**
- * Support for encoding and decoding Unicode characters in UTF-8, UTF-16, and
+ * Support for encoding and decoding Unicode characters in UTF-8, UTF-16, and
* UTF-32.
*/
+@deprecated
library dart.utf;
+import "dart:_collection-dev" show deprecated;
import "dart:async";
import "dart:collection";
part "utf_stream.dart";
@@ -16,8 +18,11 @@
// TODO(jmesserly): would be nice to have this on String (dartbug.com/6501).
/**
+ * *DEPRECATED*: Use `dart:convert` or `package:utf/utf.dart` instead.
+ *
* Provide a list of Unicode codepoints for a given string.
*/
+@deprecated
List<int> stringToCodepoints(String str) {
// Note: str.codeUnits gives us 16-bit code units on all Dart implementations.
// So we need to convert.
@@ -29,6 +34,7 @@
*
* *Deprecated* Use [String.fromCharCodes] instead.
*/
+@deprecated
String codepointsToString(List<int> codepoints) {
return new String.fromCharCodes(codepoints);
}
@@ -36,21 +42,36 @@
/**
* Invalid codepoints or encodings may be substituted with the value U+fffd.
*/
+@deprecated
const int UNICODE_REPLACEMENT_CHARACTER_CODEPOINT = 0xfffd;
+@deprecated
const int UNICODE_BOM = 0xfeff;
+@deprecated
const int UNICODE_UTF_BOM_LO = 0xff;
+@deprecated
const int UNICODE_UTF_BOM_HI = 0xfe;
+@deprecated
const int UNICODE_BYTE_ZERO_MASK = 0xff;
+@deprecated
const int UNICODE_BYTE_ONE_MASK = 0xff00;
+@deprecated
const int UNICODE_VALID_RANGE_MAX = 0x10ffff;
+@deprecated
const int UNICODE_PLANE_ONE_MAX = 0xffff;
+@deprecated
const int UNICODE_UTF16_RESERVED_LO = 0xd800;
+@deprecated
const int UNICODE_UTF16_RESERVED_HI = 0xdfff;
+@deprecated
const int UNICODE_UTF16_OFFSET = 0x10000;
+@deprecated
const int UNICODE_UTF16_SURROGATE_UNIT_0_BASE = 0xd800;
+@deprecated
const int UNICODE_UTF16_SURROGATE_UNIT_1_BASE = 0xdc00;
+@deprecated
const int UNICODE_UTF16_HI_MASK = 0xffc00;
+@deprecated
const int UNICODE_UTF16_LO_MASK = 0x3ff;
/**
@@ -123,11 +144,10 @@
}
/**
- * An Iterator<int> of codepoints built on an Iterator of UTF-16 code units.
- * The parameters can override the default Unicode replacement character. Set
- * the replacementCharacter to null to throw an ArgumentError
- * rather than replace the bad value.
+ * *DEPRECATED*: Use `package:utf/utf.dart` or, when applicable, `dart:convert`
+ * instead.
*/
+@deprecated
class Utf16CodeUnitDecoder implements Iterator<int> {
final _ListRangeIterator utf16CodeUnitIterator;
final int replacementCodepoint;
diff --git a/sdk/lib/utf/utf16.dart b/sdk/lib/utf/utf16.dart
index 3518bbb..23be863 100644
--- a/sdk/lib/utf/utf16.dart
+++ b/sdk/lib/utf/utf16.dart
@@ -5,13 +5,10 @@
part of dart.utf;
/**
- * Decodes the UTF-16 bytes as an iterable. Thus, the consumer can only convert
- * as much of the input as needed. Determines the byte order from the BOM,
- * or uses big-endian as a default. This method always strips a leading BOM.
- * Set the [replacementCodepoint] to null to throw an ArgumentError
- * rather than replace the bad value. The default value for
- * [replacementCodepoint] is U+FFFD.
+ * *DEPRECATED*: Use `package:utf/utf.dart` or, when applicable, `dart:convert`
+ * instead.
*/
+@deprecated
IterableUtf16Decoder decodeUtf16AsIterable(List<int> bytes, [int offset = 0,
int length, int replacementCodepoint =
UNICODE_REPLACEMENT_CHARACTER_CODEPOINT]) {
@@ -21,13 +18,10 @@
}
/**
- * Decodes the UTF-16BE bytes as an iterable. Thus, the consumer can only
- * convert as much of the input as needed. This method strips a leading BOM by
- * default, but can be overridden by setting the optional parameter [stripBom]
- * to false. Set the [replacementCodepoint] to null to throw an
- * ArgumentError rather than replace the bad value. The default
- * value for the [replacementCodepoint] is U+FFFD.
+ * *DEPRECATED*: Use `package:utf/utf.dart` or, when applicable, `dart:convert`
+ * instead.
*/
+@deprecated
IterableUtf16Decoder decodeUtf16beAsIterable(List<int> bytes, [int offset = 0,
int length, bool stripBom = true, int replacementCodepoint =
UNICODE_REPLACEMENT_CHARACTER_CODEPOINT]) {
@@ -37,13 +31,10 @@
}
/**
- * Decodes the UTF-16LE bytes as an iterable. Thus, the consumer can only
- * convert as much of the input as needed. This method strips a leading BOM by
- * default, but can be overridden by setting the optional parameter [stripBom]
- * to false. Set the [replacementCodepoint] to null to throw an
- * ArgumentError rather than replace the bad value. The default
- * value for the [replacementCodepoint] is U+FFFD.
+ * *DEPRECATED*: Use `package:utf/utf.dart` or, when applicable, `dart:convert`
+ * instead.
*/
+@deprecated
IterableUtf16Decoder decodeUtf16leAsIterable(List<int> bytes, [int offset = 0,
int length, bool stripBom = true, int replacementCodepoint =
UNICODE_REPLACEMENT_CHARACTER_CODEPOINT]) {
@@ -53,11 +44,10 @@
}
/**
- * Produce a String from a sequence of UTF-16 encoded bytes. This method always
- * strips a leading BOM. Set the [replacementCodepoint] to null to throw an
- * ArgumentError rather than replace the bad value. The default
- * value for the [replacementCodepoint] is U+FFFD.
+ * *DEPRECATED*: Use `package:utf/utf.dart` or, when applicable, `dart:convert`
+ * instead.
*/
+@deprecated
String decodeUtf16(List<int> bytes, [int offset = 0, int length,
int replacementCodepoint = UNICODE_REPLACEMENT_CHARACTER_CODEPOINT]) {
Utf16BytesToCodeUnitsDecoder decoder = new Utf16BytesToCodeUnitsDecoder(bytes,
@@ -68,12 +58,10 @@
}
/**
- * Produce a String from a sequence of UTF-16BE encoded bytes. This method
- * strips a leading BOM by default, but can be overridden by setting the
- * optional parameter [stripBom] to false. Set the [replacementCodepoint] to
- * null to throw an ArgumentError rather than replace the bad value.
- * The default value for the [replacementCodepoint] is U+FFFD.
+ * *DEPRECATED*: Use `package:utf/utf.dart` or, when applicable, `dart:convert`
+ * instead.
*/
+@deprecated
String decodeUtf16be(List<int> bytes, [int offset = 0, int length,
bool stripBom = true,
int replacementCodepoint = UNICODE_REPLACEMENT_CHARACTER_CODEPOINT]) {
@@ -84,12 +72,10 @@
}
/**
- * Produce a String from a sequence of UTF-16LE encoded bytes. This method
- * strips a leading BOM by default, but can be overridden by setting the
- * optional parameter [stripBom] to false. Set the [replacementCodepoint] to
- * null to throw an ArgumentError rather than replace the bad value.
- * The default value for the [replacementCodepoint] is U+FFFD.
+ * *DEPRECATED*: Use `package:utf/utf.dart` or, when applicable, `dart:convert`
+ * instead.
*/
+@deprecated
String decodeUtf16le(List<int> bytes, [int offset = 0, int length,
bool stripBom = true,
int replacementCodepoint = UNICODE_REPLACEMENT_CHARACTER_CODEPOINT]) {
@@ -100,16 +86,18 @@
}
/**
- * Produce a list of UTF-16 encoded bytes. This method prefixes the resulting
- * bytes with a big-endian byte-order-marker.
+ * *DEPRECATED*: Use `package:utf/utf.dart` or, when applicable, `dart:convert`
+ * instead.
*/
+@deprecated
List<int> encodeUtf16(String str) =>
encodeUtf16be(str, true);
/**
- * Produce a list of UTF-16BE encoded bytes. By default, this method produces
- * UTF-16BE bytes with no BOM.
+ * *DEPRECATED*: Use `package:utf/utf.dart` or, when applicable, `dart:convert`
+ * instead.
*/
+@deprecated
List<int> encodeUtf16be(String str, [bool writeBOM = false]) {
List<int> utf16CodeUnits = _stringToUtf16CodeUnits(str);
List<int> encoding =
@@ -127,9 +115,10 @@
}
/**
- * Produce a list of UTF-16LE encoded bytes. By default, this method produces
- * UTF-16LE bytes with no BOM.
+ * *DEPRECATED*: Use `package:utf/utf.dart` or, when applicable, `dart:convert`
+ * instead.
*/
+@deprecated
List<int> encodeUtf16le(String str, [bool writeBOM = false]) {
List<int> utf16CodeUnits = _stringToUtf16CodeUnits(str);
List<int> encoding =
@@ -147,18 +136,20 @@
}
/**
- * Identifies whether a List of bytes starts (based on offset) with a
- * byte-order marker (BOM).
+ * *DEPRECATED*: Use `package:utf/utf.dart` or, when applicable, `dart:convert`
+ * instead.
*/
+@deprecated
bool hasUtf16Bom(List<int> utf32EncodedBytes, [int offset = 0, int length]) {
return hasUtf16beBom(utf32EncodedBytes, offset, length) ||
hasUtf16leBom(utf32EncodedBytes, offset, length);
}
/**
- * Identifies whether a List of bytes starts (based on offset) with a
- * big-endian byte-order marker (BOM).
+ * *DEPRECATED*: Use `package:utf/utf.dart` or, when applicable, `dart:convert`
+ * instead.
*/
+@deprecated
bool hasUtf16beBom(List<int> utf16EncodedBytes, [int offset = 0, int length]) {
int end = length != null ? offset + length : utf16EncodedBytes.length;
return (offset + 2) <= end &&
@@ -167,9 +158,10 @@
}
/**
- * Identifies whether a List of bytes starts (based on offset) with a
- * little-endian byte-order marker (BOM).
+ * *DEPRECATED*: Use `package:utf/utf.dart` or, when applicable, `dart:convert`
+ * instead.
*/
+@deprecated
bool hasUtf16leBom(List<int> utf16EncodedBytes, [int offset = 0, int length]) {
int end = length != null ? offset + length : utf16EncodedBytes.length;
return (offset + 2) <= end &&
@@ -184,12 +176,10 @@
typedef _ListRangeIterator _CodeUnitsProvider();
/**
- * Return type of [decodeUtf16AsIterable] and variants. The Iterable type
- * provides an iterator on demand and the iterator will only translate bytes
- * as requested by the user of the iterator. (Note: results are not cached.)
+ * *DEPRECATED*: Use `package:utf/utf.dart` or, when applicable, `dart:convert`
+ * instead.
*/
-// TODO(floitsch): Consider removing the extend and switch to implements since
-// that's cheaper to allocate.
+@deprecated
class IterableUtf16Decoder extends IterableBase<int> {
final _CodeUnitsProvider codeunitsProvider;
final int replacementCodepoint;
@@ -202,10 +192,10 @@
}
/**
- * Convert UTF-16 encoded bytes to UTF-16 code units by grouping 1-2 bytes
- * to produce the code unit (0-(2^16)-1). Relies on BOM to determine
- * endian-ness, and defaults to BE.
+ * *DEPRECATED*: Use `package:utf/utf.dart` or, when applicable, `dart:convert`
+ * instead.
*/
+@deprecated
abstract class Utf16BytesToCodeUnitsDecoder implements _ListRangeIterator {
final _ListRangeIterator utf16EncodedBytesIterator;
final int replacementCodepoint;
@@ -287,9 +277,10 @@
}
/**
- * Convert UTF-16BE encoded bytes to utf16 code units by grouping 1-2 bytes
- * to produce the code unit (0-(2^16)-1).
+ * *DEPRECATED*: Use `package:utf/utf.dart` or, when applicable, `dart:convert`
+ * instead.
*/
+@deprecated
class Utf16beBytesToCodeUnitsDecoder extends Utf16BytesToCodeUnitsDecoder {
Utf16beBytesToCodeUnitsDecoder(List<int> utf16EncodedBytes, [
int offset = 0, int length, bool stripBom = true,
@@ -312,9 +303,10 @@
}
/**
- * Convert UTF-16LE encoded bytes to utf16 code units by grouping 1-2 bytes
- * to produce the code unit (0-(2^16)-1).
+ * *DEPRECATED*: Use `package:utf/utf.dart` or, when applicable, `dart:convert`
+ * instead.
*/
+@deprecated
class Utf16leBytesToCodeUnitsDecoder extends Utf16BytesToCodeUnitsDecoder {
Utf16leBytesToCodeUnitsDecoder(List<int> utf16EncodedBytes, [
int offset = 0, int length, bool stripBom = true,
diff --git a/sdk/lib/utf/utf32.dart b/sdk/lib/utf/utf32.dart
index acd465c..9f7293f 100644
--- a/sdk/lib/utf/utf32.dart
+++ b/sdk/lib/utf/utf32.dart
@@ -5,12 +5,10 @@
part of dart.utf;
/**
- * Decodes the UTF-32 bytes as an iterable. Thus, the consumer can only convert
- * as much of the input as needed. Determines the byte order from the BOM,
- * or uses big-endian as a default. This method always strips a leading BOM.
- * Set the replacementCharacter to null to throw an ArgumentError
- * rather than replace the bad value.
+ * *DEPRECATED*: Use `package:utf/utf.dart` or, when applicable, `dart:convert`
+ * instead.
*/
+@deprecated
IterableUtf32Decoder decodeUtf32AsIterable(List<int> bytes, [
int offset = 0, int length,
int replacementCodepoint = UNICODE_REPLACEMENT_CHARACTER_CODEPOINT]) {
@@ -19,12 +17,10 @@
}
/**
- * Decodes the UTF-32BE bytes as an iterable. Thus, the consumer can only convert
- * as much of the input as needed. This method strips a leading BOM by default,
- * but can be overridden by setting the optional parameter [stripBom] to false.
- * Set the replacementCharacter to null to throw an ArgumentError
- * rather than replace the bad value.
+ * *DEPRECATED*: Use `package:utf/utf.dart` or, when applicable, `dart:convert`
+ * instead.
*/
+@deprecated
IterableUtf32Decoder decodeUtf32beAsIterable(List<int> bytes, [
int offset = 0, int length, bool stripBom = true,
int replacementCodepoint = UNICODE_REPLACEMENT_CHARACTER_CODEPOINT]) {
@@ -34,12 +30,10 @@
}
/**
- * Decodes the UTF-32LE bytes as an iterable. Thus, the consumer can only convert
- * as much of the input as needed. This method strips a leading BOM by default,
- * but can be overridden by setting the optional parameter [stripBom] to false.
- * Set the replacementCharacter to null to throw an ArgumentError
- * rather than replace the bad value.
+ * *DEPRECATED*: Use `package:utf/utf.dart` or, when applicable, `dart:convert`
+ * instead.
*/
+@deprecated
IterableUtf32Decoder decodeUtf32leAsIterable(List<int> bytes, [
int offset = 0, int length, bool stripBom = true,
int replacementCodepoint = UNICODE_REPLACEMENT_CHARACTER_CODEPOINT]) {
@@ -49,37 +43,32 @@
}
/**
- * Produce a String from a sequence of UTF-32 encoded bytes. The parameters
- * allow an offset into a list of bytes (as int), limiting the length of the
- * values be decoded and the ability of override the default Unicode
- * replacement character. Set the replacementCharacter to null to throw an
- * ArgumentError rather than replace the bad value.
+ * *DEPRECATED*: Use `package:utf/utf.dart` or, when applicable, `dart:convert`
+ * instead.
*/
+@deprecated
String decodeUtf32(List<int> bytes, [int offset = 0, int length,
int replacementCodepoint = UNICODE_REPLACEMENT_CHARACTER_CODEPOINT]) {
return new String.fromCharCodes((new Utf32BytesDecoder(bytes, offset, length,
replacementCodepoint)).decodeRest());
}
+
/**
- * Produce a String from a sequence of UTF-32BE encoded bytes. The parameters
- * allow an offset into a list of bytes (as int), limiting the length of the
- * values be decoded and the ability of override the default Unicode
- * replacement character. Set the replacementCharacter to null to throw an
- * ArgumentError rather than replace the bad value.
+ * *DEPRECATED*: Use `package:utf/utf.dart` or, when applicable, `dart:convert`
+ * instead.
*/
+@deprecated
String decodeUtf32be(
List<int> bytes, [int offset = 0, int length, bool stripBom = true,
int replacementCodepoint = UNICODE_REPLACEMENT_CHARACTER_CODEPOINT]) =>
- new String.fromCharCodes((new Utf32beBytesDecoder(bytes, offset, length,
+ new String.fromCharCodes((new Utf32beBytesDecoder(bytes, offset, length,
stripBom, replacementCodepoint)).decodeRest());
/**
- * Produce a String from a sequence of UTF-32LE encoded bytes. The parameters
- * allow an offset into a list of bytes (as int), limiting the length of the
- * values be decoded and the ability of override the default Unicode
- * replacement character. Set the replacementCharacter to null to throw an
- * ArgumentError rather than replace the bad value.
+ * *DEPRECATED*: Use `package:utf/utf.dart` or, when applicable, `dart:convert`
+ * instead.
*/
+@deprecated
String decodeUtf32le(
List<int> bytes, [int offset = 0, int length, bool stripBom = true,
int replacementCodepoint = UNICODE_REPLACEMENT_CHARACTER_CODEPOINT]) =>
@@ -87,16 +76,18 @@
stripBom, replacementCodepoint)).decodeRest());
/**
- * Produce a list of UTF-32 encoded bytes. This method prefixes the resulting
- * bytes with a big-endian byte-order-marker.
+ * *DEPRECATED*: Use `package:utf/utf.dart` or, when applicable, `dart:convert`
+ * instead.
*/
+@deprecated
List<int> encodeUtf32(String str) =>
encodeUtf32be(str, true);
/**
- * Produce a list of UTF-32BE encoded bytes. By default, this method produces
- * UTF-32BE bytes with no BOM.
+ * *DEPRECATED*: Use `package:utf/utf.dart` or, when applicable, `dart:convert`
+ * instead.
*/
+@deprecated
List<int> encodeUtf32be(String str, [bool writeBOM = false]) {
List<int> utf32CodeUnits = stringToCodepoints(str);
List<int> encoding = new List<int>(4 * utf32CodeUnits.length +
@@ -118,9 +109,10 @@
}
/**
- * Produce a list of UTF-32LE encoded bytes. By default, this method produces
- * UTF-32BE bytes with no BOM.
+ * *DEPRECATED*: Use `package:utf/utf.dart` or, when applicable, `dart:convert`
+ * instead.
*/
+@deprecated
List<int> encodeUtf32le(String str, [bool writeBOM = false]) {
List<int> utf32CodeUnits = stringToCodepoints(str);
List<int> encoding = new List<int>(4 * utf32CodeUnits.length +
@@ -142,9 +134,10 @@
}
/**
- * Identifies whether a List of bytes starts (based on offset) with a
- * byte-order marker (BOM).
+ * *DEPRECATED*: Use `package:utf/utf.dart` or, when applicable, `dart:convert`
+ * instead.
*/
+@deprecated
bool hasUtf32Bom(
List<int> utf32EncodedBytes, [int offset = 0, int length]) {
return hasUtf32beBom(utf32EncodedBytes, offset, length) ||
@@ -152,9 +145,10 @@
}
/**
- * Identifies whether a List of bytes starts (based on offset) with a
- * big-endian byte-order marker (BOM).
+ * *DEPRECATED*: Use `package:utf/utf.dart` or, when applicable, `dart:convert`
+ * instead.
*/
+@deprecated
bool hasUtf32beBom(List<int> utf32EncodedBytes, [int offset = 0, int length]) {
int end = length != null ? offset + length : utf32EncodedBytes.length;
return (offset + 4) <= end &&
@@ -164,9 +158,10 @@
}
/**
- * Identifies whether a List of bytes starts (based on offset) with a
- * little-endian byte-order marker (BOM).
+ * *DEPRECATED*: Use `package:utf/utf.dart` or, when applicable, `dart:convert`
+ * instead.
*/
+@deprecated
bool hasUtf32leBom(List<int> utf32EncodedBytes, [int offset = 0, int length]) {
int end = length != null ? offset + length : utf32EncodedBytes.length;
return (offset + 4) <= end &&
@@ -178,12 +173,10 @@
typedef Utf32BytesDecoder Utf32BytesDecoderProvider();
/**
- * Return type of [decodeUtf32AsIterable] and variants. The Iterable type
- * provides an iterator on demand and the iterator will only translate bytes
- * as requested by the user of the iterator. (Note: results are not cached.)
+ * *DEPRECATED*: Use `package:utf/utf.dart` or, when applicable, `dart:convert`
+ * instead.
*/
-// TODO(floitsch): Consider removing the extend and switch to implements since
-// that's cheaper to allocate.
+@deprecated
class IterableUtf32Decoder extends IterableBase<int> {
final Utf32BytesDecoderProvider codeunitsProvider;
@@ -193,8 +186,10 @@
}
/**
- * Abstrace parent class converts encoded bytes to codepoints.
+ * *DEPRECATED*: Use `package:utf/utf.dart` or, when applicable, `dart:convert`
+ * instead.
*/
+@deprecated
abstract class Utf32BytesDecoder implements _ListRangeIterator {
final _ListRangeIterator utf32EncodedBytesIterator;
final int replacementCodepoint;
@@ -274,9 +269,10 @@
}
/**
- * Convert UTF-32BE encoded bytes to codepoints by grouping 4 bytes
- * to produce the unicode codepoint.
+ * *DEPRECATED*: Use `package:utf/utf.dart` or, when applicable, `dart:convert`
+ * instead.
*/
+@deprecated
class Utf32beBytesDecoder extends Utf32BytesDecoder {
Utf32beBytesDecoder(List<int> utf32EncodedBytes, [int offset = 0,
int length, bool stripBom = true,
@@ -303,9 +299,10 @@
}
/**
- * Convert UTF-32BE encoded bytes to codepoints by grouping 4 bytes
- * to produce the unicode codepoint.
+ * *DEPRECATED*: Use `package:utf/utf.dart` or, when applicable, `dart:convert`
+ * instead.
*/
+@deprecated
class Utf32leBytesDecoder extends Utf32BytesDecoder {
Utf32leBytesDecoder(List<int> utf32EncodedBytes, [int offset = 0,
int length, bool stripBom = true,
diff --git a/sdk/lib/utf/utf8.dart b/sdk/lib/utf/utf8.dart
index 7543865..5867b96 100644
--- a/sdk/lib/utf/utf8.dart
+++ b/sdk/lib/utf/utf8.dart
@@ -4,30 +4,100 @@
part of dart.utf;
+/**
+ * *DEPRECATED*: Use `package:utf/utf.dart` or, when applicable, `dart:convert`
+ * instead.
+ */
+@deprecated
const int _UTF8_ONE_BYTE_MAX = 0x7f;
+/**
+ * *DEPRECATED*: Use `package:utf/utf.dart` or, when applicable, `dart:convert`
+ * instead.
+ */
+@deprecated
const int _UTF8_TWO_BYTE_MAX = 0x7ff;
+/**
+ * *DEPRECATED*: Use `package:utf/utf.dart` or, when applicable, `dart:convert`
+ * instead.
+ */
+@deprecated
const int _UTF8_THREE_BYTE_MAX = 0xffff;
+/**
+ * *DEPRECATED*: Use `package:utf/utf.dart` or, when applicable, `dart:convert`
+ * instead.
+ */
+@deprecated
const int _UTF8_LO_SIX_BIT_MASK = 0x3f;
+/**
+ * *DEPRECATED*: Use `package:utf/utf.dart` or, when applicable, `dart:convert`
+ * instead.
+ */
+@deprecated
const int _UTF8_FIRST_BYTE_OF_TWO_BASE = 0xc0;
+/**
+ * *DEPRECATED*: Use `package:utf/utf.dart` or, when applicable, `dart:convert`
+ * instead.
+ */
+@deprecated
const int _UTF8_FIRST_BYTE_OF_THREE_BASE = 0xe0;
+/**
+ * *DEPRECATED*: Use `package:utf/utf.dart` or, when applicable, `dart:convert`
+ * instead.
+ */
+@deprecated
const int _UTF8_FIRST_BYTE_OF_FOUR_BASE = 0xf0;
+/**
+ * *DEPRECATED*: Use `package:utf/utf.dart` or, when applicable, `dart:convert`
+ * instead.
+ */
+@deprecated
const int _UTF8_FIRST_BYTE_OF_FIVE_BASE = 0xf8;
+/**
+ * *DEPRECATED*: Use `package:utf/utf.dart` or, when applicable, `dart:convert`
+ * instead.
+ */
+@deprecated
const int _UTF8_FIRST_BYTE_OF_SIX_BASE = 0xfc;
+/**
+ * *DEPRECATED*: Use `package:utf/utf.dart` or, when applicable, `dart:convert`
+ * instead.
+ */
+@deprecated
const int _UTF8_FIRST_BYTE_OF_TWO_MASK = 0x1f;
+/**
+ * *DEPRECATED*: Use `package:utf/utf.dart` or, when applicable, `dart:convert`
+ * instead.
+ */
+@deprecated
const int _UTF8_FIRST_BYTE_OF_THREE_MASK = 0xf;
+/**
+ * *DEPRECATED*: Use `package:utf/utf.dart` or, when applicable, `dart:convert`
+ * instead.
+ */
+@deprecated
const int _UTF8_FIRST_BYTE_OF_FOUR_MASK = 0x7;
+/**
+ * *DEPRECATED*: Use `package:utf/utf.dart` or, when applicable, `dart:convert`
+ * instead.
+ */
+@deprecated
const int _UTF8_FIRST_BYTE_BOUND_EXCL = 0xfe;
+/**
+ * *DEPRECATED*: Use `package:utf/utf.dart` or, when applicable, `dart:convert`
+ * instead.
+ */
+@deprecated
const int _UTF8_SUBSEQUENT_BYTE_BASE = 0x80;
/**
- * Decodes the UTF-8 bytes as an iterable. Thus, the consumer can only convert
- * as much of the input as needed. Set the replacementCharacter to null to
- * throw an ArgumentError rather than replace the bad value.
+ * *DEPRECATED*: Use `package:utf/utf.dart` or, when applicable, `dart:convert`
+ * instead.
*/
+@deprecated
IterableUtf8Decoder decodeUtf8AsIterable(List<int> bytes, [int offset = 0,
int length,
int replacementCodepoint = UNICODE_REPLACEMENT_CHARACTER_CODEPOINT]) {
@@ -35,12 +105,10 @@
}
/**
- * Produce a String from a List of UTF-8 encoded bytes. The parameters
- * can set an offset into a list of bytes (as int), limit the length of the
- * values to be decoded, and override the default Unicode replacement character.
- * Set the replacementCharacter to null to throw an ArgumentError
- * rather than replace the bad value.
+ * *DEPRECATED*: Use `package:utf/utf.dart` or, when applicable, `dart:convert`
+ * instead.
*/
+@deprecated
String decodeUtf8(List<int> bytes, [int offset = 0, int length,
int replacementCodepoint = UNICODE_REPLACEMENT_CHARACTER_CODEPOINT]) {
return new String.fromCharCodes(
@@ -49,8 +117,10 @@
}
/**
- * Produce a sequence of UTF-8 encoded bytes from the provided string.
+ * *DEPRECATED*: Use `package:utf/utf.dart` or, when applicable, `dart:convert`
+ * instead.
*/
+@deprecated
List<int> encodeUtf8(String str) =>
codepointsToUtf8(stringToCodepoints(str));
@@ -65,8 +135,10 @@
}
/**
- * Encode code points as UTF-8 code units.
+ * *DEPRECATED*: Use `package:utf/utf.dart` or, when applicable, `dart:convert`
+ * instead.
*/
+@deprecated
List<int> codepointsToUtf8(
List<int> codepoints, [int offset = 0, int length]) {
_ListRange source = new _ListRange(codepoints, offset, length);
@@ -115,8 +187,11 @@
return encoded;
}
-// Because UTF-8 specifies byte order, we do not have to follow the pattern
-// used by UTF-16 & UTF-32 regarding byte order.
+/**
+ * *DEPRECATED*: Use `package:utf/utf.dart` or, when applicable, `dart:convert`
+ * instead.
+ */
+@deprecated
List<int> utf8ToCodepoints(
List<int> utf8EncodedBytes, [int offset = 0, int length,
int replacementCodepoint = UNICODE_REPLACEMENT_CHARACTER_CODEPOINT]) {
@@ -125,12 +200,10 @@
}
/**
- * Return type of [decodeUtf8AsIterable] and variants. The Iterable type
- * provides an iterator on demand and the iterator will only translate bytes
- * as requested by the user of the iterator. (Note: results are not cached.)
+ * *DEPRECATED*: Use `package:utf/utf.dart` or, when applicable, `dart:convert`
+ * instead.
*/
-// TODO(floitsch): Consider removing the extend and switch to implements since
-// that's cheaper to allocate.
+@deprecated
class IterableUtf8Decoder extends IterableBase<int> {
final List<int> bytes;
final int offset;
@@ -145,13 +218,10 @@
}
/**
- * Provides an iterator of Unicode codepoints from UTF-8 encoded bytes. The
- * parameters can set an offset into a list of bytes (as int), limit the length
- * of the values to be decoded, and override the default Unicode replacement
- * character. Set the replacementCharacter to null to throw an
- * ArgumentError rather than replace the bad value. The return value
- * from this method can be used as an Iterable (e.g. in a for-loop).
+ * *DEPRECATED*: Use `package:utf/utf.dart` or, when applicable, `dart:convert`
+ * instead.
*/
+@deprecated
class Utf8Decoder implements Iterator<int> {
final _ListRangeIterator utf8EncodedBytesIterator;
final int replacementCodepoint;
diff --git a/sdk/lib/utf/utf_stream.dart b/sdk/lib/utf/utf_stream.dart
index 8440313..590790a 100644
--- a/sdk/lib/utf/utf_stream.dart
+++ b/sdk/lib/utf/utf_stream.dart
@@ -93,8 +93,10 @@
}
/**
- * StringTransformer that decodes a stream of UTF-8 encoded bytes.
+ * *DEPRECATED*: Use `package:utf/utf.dart` or, when applicable, `dart:convert`
+ * instead.
*/
+@deprecated
class Utf8DecoderTransformer extends _StringDecoder {
Utf8DecoderTransformer(
[int replacementChar = UNICODE_REPLACEMENT_CHARACTER_CODEPOINT])
@@ -160,8 +162,10 @@
}
/**
- * StringTransformer that UTF-8 encodes a stream of strings.
+ * *DEPRECATED*: Use `package:utf/utf.dart` or, when applicable, `dart:convert`
+ * instead.
*/
+@deprecated
class Utf8EncoderTransformer extends _StringEncoder {
List<int> _processString(String string) {
var bytes = [];
diff --git a/tests/co19/co19-analyzer.status b/tests/co19/co19-analyzer.status
index 2859980..20082fc 100644
--- a/tests/co19/co19-analyzer.status
+++ b/tests/co19/co19-analyzer.status
@@ -16,17 +16,20 @@
Language/15_Types/4_Interface_Types_A11_t01: Skip
Language/15_Types/4_Interface_Types_A11_t02: Skip
-# co19 issue #380, Strings class has been removed
-LibTest/core/RegExp/Pattern_semantics/firstMatch_CharacterClassEscape_A04_t01: fail, OK
+# TBF: "class B1 = A with M1;", typedef cannot be used for mixins
+Language/09_Mixins/1_Mixin_Application_A01_t01: Fail
-# co19 issue #400, collection library reorg
-LibTest/core/String/concat_A01_t01: fail, OK
-LibTest/core/String/concat_A02_t01: fail, OK
-LibTest/core/Set/isSubsetOf_A01_t01: fail, OK
-LibTest/core/Set/isSubsetOf_A01_t02: fail, OK
+# TBF: It is a compile-time error if the key of an entry in a constant map literal is an instance of a class that implements the operator == unless the key is a string or integer.
+Language/12_Expressions/07_Maps_A13_t01: Fail
-# co19 issue #425, Only static fields can be declared as 'const'
-Language/07_Classes/07_Classes_A02_t11: fail, OK
+# TBF: malformed or malbounded type in "conts" is static warning
+Language/12_Expressions/12_Instance_Creation_A01_t08: Fail
+
+# TBF: typedef self reference
+Language/15_Types/3_Type_Declarations/1_Typedef_A07_t08: Fail
+Language/15_Types/3_Type_Declarations/1_Typedef_A07_t09: Fail
+
+
# co19 issue #442, undefined name "Expect"
Language/15_Types/4_Interface_Types_A08_t03: fail, OK
@@ -80,47 +83,63 @@
# co19 issue #609, return type of "factory M" is M, so we need static warning for "return;".
Language/13_Statements/11_Return_A07_t01: fail, OK
-Language/09_Mixins/1_Mixin_Application_A01_t01: Fail # co19-roll r607: Please triage this failure
-Language/12_Expressions/01_Constants_A22_t01: Fail # co19-roll r607: Please triage this failure
-Language/12_Expressions/07_Maps_A13_t01: Fail # co19-roll r607: Please triage this failure
-Language/12_Expressions/12_Instance_Creation_A01_t08: Fail # co19-roll r607: Please triage this failure
-Language/12_Expressions/13_Property_Extraction_A02_t02: Fail # co19-roll r607: Please triage this failure
-Language/12_Expressions/13_Property_Extraction_A04_t02: Fail # co19-roll r607: Please triage this failure
-Language/12_Expressions/13_Property_Extraction_A04_t03: Fail # co19-roll r607: Please triage this failure
-Language/12_Expressions/15_Method_Invocation/1_Ordinary_Invocation_A03_t03: Fail # co19-roll r607: Please triage this failure
-Language/12_Expressions/15_Method_Invocation/1_Ordinary_Invocation_A03_t04: Fail # co19-roll r607: Please triage this failure
-Language/12_Expressions/15_Method_Invocation/1_Ordinary_Invocation_A04_t04: Fail # co19-roll r607: Please triage this failure
-Language/12_Expressions/15_Method_Invocation/4_Super_Invocation_A02_t05: Fail # co19-roll r607: Please triage this failure
-Language/12_Expressions/16_Getter_Lookup_A02_t05: Fail # co19-roll r607: Please triage this failure
-Language/12_Expressions/16_Getter_Lookup_A02_t06: Fail # co19-roll r607: Please triage this failure
-Language/12_Expressions/17_Getter_Invocation_A07_t01: Fail # co19-roll r607: Please triage this failure
-Language/12_Expressions/17_Getter_Invocation_A07_t02: Fail # co19-roll r607: Please triage this failure
-Language/12_Expressions/18_Assignment_A01_t07: Fail # co19-roll r607: Please triage this failure
-Language/12_Expressions/18_Assignment_A04_t09: Fail # co19-roll r607: Please triage this failure
-Language/13_Statements/02_Expression_Statements_A01_t13: Fail # co19-roll r607: Please triage this failure
-Language/15_Types/3_Type_Declarations/1_Typedef_A07_t08: Fail # co19-roll r607: Please triage this failure
-Language/15_Types/3_Type_Declarations/1_Typedef_A07_t09: Fail # co19-roll r607: Please triage this failure
-LibTest/collection/HasNextIterator/HasNextIterator_A01_t01: Fail # co19-roll r607: Please triage this failure
-LibTest/collection/LinkedHashSet/LinkedHashSet.from_A01_t01: Fail # co19-roll r607: Please triage this failure
-LibTest/collection/LinkedHashSet/LinkedHashSet_class_A01_t01: Fail # co19-roll r607: Please triage this failure
-LibTest/collection/LinkedList/LinkedList_A01_t01: Fail # co19-roll r607: Please triage this failure
-LibTest/collection/LinkedList/first_A01_t02: Fail # co19-roll r607: Please triage this failure
-LibTest/collection/LinkedList/reduce_A01_t01: Fail # co19-roll r607: Please triage this failure
-LibTest/core/Invocation/isAccessor_A01_t01: Fail # co19-roll r607: Please triage this failure
-LibTest/core/Invocation/isAccessor_A01_t02: Fail # co19-roll r607: Please triage this failure
-LibTest/core/Invocation/isGetter_A01_t01: Fail # co19-roll r607: Please triage this failure
-LibTest/core/Invocation/isGetter_A01_t02: Fail # co19-roll r607: Please triage this failure
-LibTest/core/Invocation/isMethod_A01_t01: Fail # co19-roll r607: Please triage this failure
-LibTest/core/Invocation/isMethod_A01_t02: Fail # co19-roll r607: Please triage this failure
-LibTest/core/Invocation/isSetter_A01_t01: Fail # co19-roll r607: Please triage this failure
-LibTest/core/Invocation/isSetter_A01_t02: Fail # co19-roll r607: Please triage this failure
-LibTest/core/Invocation/memberName_A01_t01: Fail # co19-roll r607: Please triage this failure
-LibTest/core/Invocation/namedArguments_A01_t01: Fail # co19-roll r607: Please triage this failure
-LibTest/core/Invocation/positionalArguments_A01_t01: Fail # co19-roll r607: Please triage this failure
-LibTest/core/RuneIterator/currentAsString_A01_t02: Fail # co19-roll r607: Please triage this failure
-LibTest/core/RuneIterator/current_A01_t02: Fail # co19-roll r607: Please triage this failure
-LibTest/core/Runes/isEmpty_A01_t02: Fail # co19-roll r607: Please triage this failure
-LibTest/core/Runes/isNotEmpty_A01_t02: Fail # co19-roll r607: Please triage this failure
-LibTest/core/Runes/lastWhere_A02_t01: Fail # co19-roll r607: Please triage this failure
-LibTest/core/Runes/length_A01_t02: Fail # co19-roll r607: Please triage this failure
-LibTest/core/Symbol/Symbol_A01_t04: Fail # co19-roll r607: Please triage this failure
+# co19 issue #613: @static-warning missing, only runtime behavior is tested
+Language/12_Expressions/13_Property_Extraction_A02_t02: Fail, OK
+Language/12_Expressions/13_Property_Extraction_A04_t02: Fail, OK
+Language/12_Expressions/13_Property_Extraction_A04_t03: Fail, OK
+Language/12_Expressions/17_Getter_Invocation_A07_t01: Fail, OK
+Language/12_Expressions/17_Getter_Invocation_A07_t02: Fail, OK
+Language/12_Expressions/18_Assignment_A01_t07: Fail, OK
+Language/12_Expressions/18_Assignment_A04_t09: Fail, OK
+LibTest/core/Invocation/isAccessor_A01_t01: Fail, OK
+LibTest/core/Invocation/isAccessor_A01_t02: Fail, OK
+LibTest/core/Invocation/isGetter_A01_t01: Fail, OK
+LibTest/core/Invocation/isGetter_A01_t02: Fail, OK
+LibTest/core/Invocation/isMethod_A01_t01: Fail, OK
+LibTest/core/Invocation/isMethod_A01_t02: Fail, OK
+LibTest/core/Invocation/isSetter_A01_t01: Fail, OK
+LibTest/core/Invocation/isSetter_A01_t02: Fail, OK
+LibTest/core/Invocation/memberName_A01_t01: Fail, OK
+LibTest/core/Invocation/namedArguments_A01_t01: Fail, OK
+LibTest/core/Invocation/positionalArguments_A01_t01: Fail, OK
+LibTest/core/Symbol/Symbol_A01_t04: Fail, OK
+
+# co19 issue #614: abstract class
+Language/12_Expressions/15_Method_Invocation/1_Ordinary_Invocation_A03_t03: Fail, OK
+Language/12_Expressions/15_Method_Invocation/1_Ordinary_Invocation_A03_t04: Fail, OK
+Language/12_Expressions/16_Getter_Lookup_A02_t05: Fail, OK
+Language/12_Expressions/16_Getter_Lookup_A02_t06: Fail, OK
+
+# co19 issue #615: Expect import missing
+Language/12_Expressions/15_Method_Invocation/1_Ordinary_Invocation_A03_t03: Fail, OK
+LibTest/collection/LinkedList/LinkedList_A01_t01: Fail, OK
+
+# co19 issue #616: X required argument(s) expected, but Y found
+Language/12_Expressions/15_Method_Invocation/1_Ordinary_Invocation_A04_t04: Fail, OK
+Language/12_Expressions/15_Method_Invocation/4_Super_Invocation_A02_t05: Fail, OK
+
+# co19 issue #617: "hasNext" is not a function; "Expec"
+LibTest/collection/HasNextIterator/HasNextIterator_A01_t01: Fail, OK
+
+# co19 issue #618: Just a mess - mix of Map and Set
+LibTest/collection/LinkedHashSet/LinkedHashSet.from_A01_t01: Fail, OK
+LibTest/collection/LinkedHashSet/LinkedHashSet_class_A01_t01: Fail, OK
+LibTest/collection/LinkedList/first_A01_t02: Fail, OK
+
+# co19 issue #619: 1 required argument(s) expected, but 0 found
+LibTest/collection/LinkedList/reduce_A01_t01: Fail, OK
+
+# co19 issue #620: The name 'NoSuchMethoError' is not a type and cannot be used in an on-catch clause
+LibTest/core/RuneIterator/currentAsString_A01_t02: Fail, OK
+LibTest/core/RuneIterator/current_A01_t02: Fail, OK
+LibTest/core/Runes/length_A01_t02: Fail, OK
+
+# co19 issue #621: Undefined name 'runes'
+LibTest/core/Runes/isEmpty_A01_t02: Fail, OK
+LibTest/core/Runes/isNotEmpty_A01_t02: Fail, OK
+
+# co19 issue #622: Undefined class 'Int16List.fromList'
+LibTest/core/Runes/lastWhere_A02_t01: Fail, OK
+
+# co19 issue #623: main() { {}; } is block and empty statement, not a map
+Language/13_Statements/02_Expression_Statements_A01_t13: Fail, OK
diff --git a/tests/co19/co19-co19.status b/tests/co19/co19-co19.status
index 5dcead1..8e0d9e1 100644
--- a/tests/co19/co19-co19.status
+++ b/tests/co19/co19-co19.status
@@ -23,7 +23,6 @@
Language/09_Mixins/1_Mixin_Application_A01_t01: CompileTimeError # co19-roll r607: Please triage this failure
LibTest/collection/LinkedHashSet/LinkedHashSet_class_A01_t01: CompileTimeError # co19-roll r607: Please triage this failure
LibTest/collection/LinkedList/first_A01_t02: CompileTimeError # co19-roll r607: Please triage this failure
-Language/12_Expressions/18_Assignment_A01_t07: RuntimeError # co19-roll r607: Please triage this failure
Language/12_Expressions/18_Assignment_A04_t09: RuntimeError # co19-roll r607: Please triage this failure
Language/13_Statements/04_Local_Function_Declaration_A04_t01: MissingCompileTimeError # co19-roll r607: Please triage this failure
Language/13_Statements/02_Expression_Statements_A01_t13: MissingCompileTimeError # co19-roll r607: Please triage this failure
diff --git a/tests/co19/co19-dart2dart.status b/tests/co19/co19-dart2dart.status
index 5da24a9..df86f4c 100644
--- a/tests/co19/co19-dart2dart.status
+++ b/tests/co19/co19-dart2dart.status
@@ -36,6 +36,7 @@
Language/07_Classes/6_Constructors/3_Constant_Constructors_A05_t04: Fail # Issue 13652
Language/07_Classes/6_Constructors_A02_t01: Fail # http://dartbug.com/5519
Language/12_Expressions/01_Constants_A03_t01: Fail # Issue 13652
+Language/12_Expressions/18_Assignment_A01_t07: RuntimeError # Issue 13494
Language/13_Statements/09_Switch_A02_t04: Fail # co19 issue 605
Language/12_Expressions/00_Object_Identity/1_Object_Identity_A04_t02: Fail # co19 issue 606
@@ -67,6 +68,12 @@
LibTest/math/sin_A01_t01: Fail # Inherited from VM.
LibTest/math/tan_A01_t01: Fail # Issue co19 - 44
LibTest/typed_data/Float32x4/clamp_A01_t01: RuntimeError # co19 Issue 600
+Language/05_Variables/05_Variables_A06_t01: CompileTimeError, OK # dartbug.com/12543
+Language/05_Variables/05_Variables_A06_t02: CompileTimeError, OK # dartbug.com/12543
+Language/05_Variables/05_Variables_A06_t03: CompileTimeError, OK # dartbug.com/12543
+Language/05_Variables/05_Variables_A06_t04: CompileTimeError, OK # dartbug.com/12543
+Language/05_Variables/05_Variables_A06_t05: CompileTimeError, OK # dartbug.com/12543
+Language/05_Variables/05_Variables_A06_t06: CompileTimeError, OK # dartbug.com/12543
[ $compiler == dart2dart && $system == windows ]
@@ -188,4 +195,4 @@
LibTest/json/stringify_A02_t01: fail # co19-roll r587: Please triage this failure
LibTest/json/stringify_A03_t02: fail # co19-roll r587: Please triage this failure
LibTest/json/printOn_A02_t01: fail # co19-roll r587: Please triage this failure
-LibTest/json/printOn_A03_t02: fail # co19-roll r587: Please triage this failure
\ No newline at end of file
+LibTest/json/printOn_A03_t02: fail # co19-roll r587: Please triage this failure
diff --git a/tests/co19/co19-dart2js.status b/tests/co19/co19-dart2js.status
index 0021c0c..7af904e 100644
--- a/tests/co19/co19-dart2js.status
+++ b/tests/co19/co19-dart2js.status
@@ -161,6 +161,13 @@
# can understand so he can file a bug later.
#
[ $compiler == dart2js ]
+Language/05_Variables/05_Variables_A06_t01: CompileTimeError, OK # dartbug.com/12543
+Language/05_Variables/05_Variables_A06_t02: CompileTimeError, OK # dartbug.com/12543
+Language/05_Variables/05_Variables_A06_t03: CompileTimeError, OK # dartbug.com/12543
+Language/05_Variables/05_Variables_A06_t04: CompileTimeError, OK # dartbug.com/12543
+Language/05_Variables/05_Variables_A06_t05: CompileTimeError, OK # dartbug.com/12543
+Language/05_Variables/05_Variables_A06_t06: CompileTimeError, OK # dartbug.com/12543
+
Language/03_Overview/2_Privacy_A01_t09: RuntimeError, OK # co19 issue 198
Language/03_Overview/2_Privacy_A01_t11: Pass, OK # co19 issue 316
Language/06_Functions/4_External_Functions_A01_t01: CompileTimeError, OK # http://dartbug.com/5021
diff --git a/tests/co19/co19-dartium.status b/tests/co19/co19-dartium.status
index 471d509..7affca6 100644
--- a/tests/co19/co19-dartium.status
+++ b/tests/co19/co19-dartium.status
@@ -2,6 +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.
+[ $compiler == none && $runtime == drt ]
+*: Skip # running co19 tests on content_shell would make our dartium cycle-times very long
+
[ $compiler == none && $runtime == dartium ]
Language/03_Overview/2_Privacy_A01_t06: Fail # Issue 13719: Please triage this failure.
Language/05_Variables/05_Variables_A05_t01: Fail # Issue 13719: Please triage this failure.
@@ -24,6 +27,8 @@
Language/12_Expressions/01_Constants_A16_t02: Fail # Issue 13719: Please triage this failure.
Language/12_Expressions/01_Constants_A16_t04: Fail # Issue 13719: Please triage this failure.
Language/12_Expressions/01_Constants_A16_t05: Fail # Issue 13719: Please triage this failure.
+Language/12_Expressions/05_Strings_A02_t46: Fail # Issue 13719: Please triage this failure.
+Language/12_Expressions/05_Strings_A02_t48: Fail # Issue 13719: Please triage this failure.
Language/12_Expressions/12_Instance_Creation/1_New_A06_t12: Fail # Issue 13719: Please triage this failure.
Language/12_Expressions/12_Instance_Creation/1_New_A09_t09: Fail # Issue 13719: Please triage this failure.
Language/12_Expressions/12_Instance_Creation/2_Const_A10_t01: Fail # Issue 13719: Please triage this failure.
@@ -77,6 +82,7 @@
LibTest/core/double/floor_A01_t04: Fail # Issue 13719: Please triage this failure.
LibTest/core/double/round_A01_t02: Fail # Issue 13719: Please triage this failure.
LibTest/core/double/round_A01_t04: Fail # Issue 13719: Please triage this failure.
+LibTest/core/int/operator_left_shift_A01_t02: Pass, Fail # Issue 13719: Please triage this failure.
LibTest/core/int/toRadixString_A01_t01: Fail # Issue 13719: Please triage this failure.
LibTest/core/Invocation/namedArguments_A01_t01: Fail # co19-roll r607: Please triage this failure
LibTest/core/Invocation/positionalArguments_A01_t01: Fail # co19-roll r607: Please triage this failure
@@ -111,7 +117,11 @@
LibTest/isolate/IsolateSink/addError_A01_t02: Fail # Issue 13719: Please triage this failure.
LibTest/isolate/IsolateStream/any_A02_t01: Fail # Issue 13719: Please triage this failure.
LibTest/isolate/ReceivePort/receive_A01_t02: Fail # Issue 13719: Please triage this failure.
+LibTest/isolate/ReceivePort/toSendPort_A01_t02: Pass, Fail # Issue 13719: Please triage this failure.
LibTest/isolate/SendPort/send_A01_t01: Fail # Issue 13719: Please triage this failure.
+LibTest/math/acos_A01_t01: Pass, Fail # Issue 13719: Please triage this failure.
+LibTest/math/asin_A01_t01: Pass, Fail # Issue 13719: Please triage this failure.
+LibTest/math/atan_A01_t01: Pass, Fail # Issue 13719: Please triage this failure.
LibTest/typed_data/ByteData/elementSizeInBytes_A01_t01: Fail # Issue 13719: Please triage this failure.
LibTest/typed_data/Float32x4/clamp_A01_t01: Fail # Issue 13719: Please triage this failure.
-LibTest/typed_data/Int8List/Int8List.fromList_A01_t02: Fail # Issue 13719: Please triage this failure.
\ No newline at end of file
+LibTest/typed_data/Int8List/Int8List.fromList_A01_t02: Fail # Issue 13719: Please triage this failure.
diff --git a/tests/co19/co19-runtime.status b/tests/co19/co19-runtime.status
index 6796d88..0e1840f 100644
--- a/tests/co19/co19-runtime.status
+++ b/tests/co19/co19-runtime.status
@@ -74,6 +74,7 @@
Language/12_Expressions/12_Instance_Creation/1_New_A09_t09: fail # Dart issue 1372
Language/12_Expressions/12_Instance_Creation/2_Const_A10_t01: fail # co19 issue 525
Language/12_Expressions/15_Method_Invocation/3_Static_Invocation_A04_t09: fail # Dart issue 12549
+Language/12_Expressions/18_Assignment_A01_t07: RuntimeError # Issue 13494
Language/12_Expressions/30_Identifier_Reference_A08_t02: fail # Dart issue 12593
Language/12_Expressions/32_Type_Test_A04_t02: fail # co19 issue 503
Language/12_Expressions/32_Type_Test_A04_t03: fail # co19 issue 534
@@ -150,8 +151,3 @@
LibTest/core/Symbol/Symbol_A01_t03: RuntimeError # co19-roll r607: Please triage this failure
LibTest/core/Symbol/Symbol_A01_t05: RuntimeError # co19-roll r607: Please triage this failure
-[ $compiler == none && $runtime == vm && $mode == debug && $checked ]
-LibTest/collection/LinkedList/add_A01_t01: Pass, Crash # co19-roll r607: Please triage this failure
-LibTest/collection/LinkedList/iterator_current_A01_t01: Pass, Crash # co19-roll r607: Please triage this failure
-LibTest/collection/LinkedList/single_A01_t01: Pass, Crash # co19-roll r607: Please triage this failure
-
diff --git a/tests/compiler/dart2js/dart_backend_test.dart b/tests/compiler/dart2js/dart_backend_test.dart
index 5469890..c57dfb3 100644
--- a/tests/compiler/dart2js/dart_backend_test.dart
+++ b/tests/compiler/dart2js/dart_backend_test.dart
@@ -179,8 +179,8 @@
}
testVariableDefinitions() {
- testDart2Dart('main(){var x,y;final String s;}');
- testDart2Dart('main(){final int x,y;final String s;}');
+ testDart2Dart('main(){var x,y;final String s=null;}');
+ testDart2Dart('main(){final int x=0,y=0;final String s=null;}');
testDart2Dart('foo(f,g){}main(){foo(1,2);}');
testDart2Dart('foo(f(arg)){}main(){foo(main);}');
// A couple of static/finals inside a class.
@@ -205,7 +205,7 @@
}
testAbstractClass() {
- testDart2Dart('main(){A.foo;}abstract class A{final static num foo;}');
+ testDart2Dart('main(){A.foo;}abstract class A{final static num foo=0;}');
}
testConflictSendsRename() {
diff --git a/tests/compiler/dart2js/diagnose_ambiguous_test.dart b/tests/compiler/dart2js/diagnose_ambiguous_test.dart
index 0ebba79..2347825 100644
--- a/tests/compiler/dart2js/diagnose_ambiguous_test.dart
+++ b/tests/compiler/dart2js/diagnose_ambiguous_test.dart
@@ -33,12 +33,12 @@
asyncTest(() => compiler.run(Uri.parse('memory:main.dart')).then((_) {
diagnostics.sort();
var expected = [
- "memory:exporter.dart:43:47:Info: 'function(hest)' is defined here."
+ "memory:exporter.dart:43:47:Info: 'hest' is defined here."
":info",
- "memory:library.dart:41:45:Info: 'function(hest)' is defined here."
+ "memory:library.dart:41:45:Info: 'hest' is defined here."
":info",
- "memory:main.dart:0:22:Info: 'function(hest)' is imported here.:info",
- "memory:main.dart:23:46:Info: 'function(hest)' is imported here.:info",
+ "memory:main.dart:0:22:Info: 'hest' is imported here.:info",
+ "memory:main.dart:23:46:Info: 'hest' is imported here.:info",
"memory:main.dart:86:90:Error: Duplicate import of 'hest'.:error"
];
Expect.listEquals(expected, diagnostics);
diff --git a/tests/compiler/dart2js/type_checker_test.dart b/tests/compiler/dart2js/type_checker_test.dart
index 95c0e0d..ca31c6a 100644
--- a/tests/compiler/dart2js/type_checker_test.dart
+++ b/tests/compiler/dart2js/type_checker_test.dart
@@ -52,6 +52,11 @@
testOperatorsAssignability,
testFieldInitializers,
testTypeVariableExpressions,
+ testTypeVariableLookup1,
+ testTypeVariableLookup2,
+ testTypeVariableLookup3,
+ testFunctionTypeLookup,
+ testTypedefLookup,
testTypeLiteral,
testInitializers];
for (Function test in tests) {
@@ -1074,6 +1079,121 @@
analyzeIn(method, "{ T + 1; }", MessageKind.OPERATOR_NOT_FOUND);
}
+void testTypeVariableLookup1() {
+ String script = """
+class Foo {
+ int field;
+ void method(int argument) {}
+ int operator +(Foo foo) {}
+ int get getter => 21;
+}
+
+class Test<S extends Foo, T> {
+ S s;
+ T t;
+ test() {}
+}
+""";
+
+ LibraryElement library = mockLibrary(compiler, script);
+ compiler.parseScript(script, library);
+ ClassElement classTest = library.find(const SourceString("Test"));
+ classTest.ensureResolved(compiler);
+ FunctionElement methodTest =
+ classTest.lookupLocalMember(const SourceString("test"));
+
+ test(String expression, [message]) {
+ analyzeIn(methodTest, "{ $expression; }", message);
+ }
+
+ test('s.field');
+ test('s.method(1)');
+ test('s + s');
+ test('s.getter');
+
+ test('t.toString');
+ test('t.field', MEMBER_NOT_FOUND);
+ test('t.method(1)', MessageKind.METHOD_NOT_FOUND);
+ test('t + t', MessageKind.OPERATOR_NOT_FOUND);
+ test('t.getter', MEMBER_NOT_FOUND);
+
+ test('s.field = "hest"', NOT_ASSIGNABLE);
+ test('s.method("hest")', NOT_ASSIGNABLE);
+ test('s + "hest"', NOT_ASSIGNABLE);
+ test('String v = s.getter', NOT_ASSIGNABLE);
+}
+
+void testTypeVariableLookup2() {
+ String script = """
+class Foo {
+ int field;
+ void method(int argument) {}
+ int operator +(Foo foo) {}
+ int get getter => 21;
+}
+
+class Test<S extends T, T extends Foo> {
+ S s;
+ test() {}
+}""";
+
+ LibraryElement library = mockLibrary(compiler, script);
+ compiler.parseScript(script, library);
+ ClassElement classTest = library.find(const SourceString("Test"));
+ classTest.ensureResolved(compiler);
+ FunctionElement methodTest =
+ classTest.lookupLocalMember(const SourceString("test"));
+
+ test(String expression, [message]) {
+ analyzeIn(methodTest, "{ $expression; }", message);
+ }
+
+ test('s.field');
+ test('s.method(1)');
+ test('s + s');
+ test('s.getter');
+}
+
+void testTypeVariableLookup3() {
+ String script = """
+class Test<S extends T, T extends S> {
+ S s;
+ test() {}
+}""";
+
+ LibraryElement library = mockLibrary(compiler, script);
+ compiler.parseScript(script, library);
+ ClassElement classTest = library.find(const SourceString("Test"));
+ classTest.ensureResolved(compiler);
+ FunctionElement methodTest =
+ classTest.lookupLocalMember(const SourceString("test"));
+
+ test(String expression, [message]) {
+ analyzeIn(methodTest, "{ $expression; }", message);
+ }
+
+ test('s.toString');
+ test('s.field', MEMBER_NOT_FOUND);
+ test('s.method(1)', MessageKind.METHOD_NOT_FOUND);
+ test('s + s', MessageKind.OPERATOR_NOT_FOUND);
+ test('s.getter', MEMBER_NOT_FOUND);
+}
+
+void testFunctionTypeLookup() {
+ analyze('(int f(int)) => f.toString;');
+ analyze('(int f(int)) => f.toString();');
+ analyze('(int f(int)) => f.foo;', MEMBER_NOT_FOUND);
+ analyze('(int f(int)) => f.foo();', MessageKind.METHOD_NOT_FOUND);
+}
+
+void testTypedefLookup() {
+ compiler.parseScript("typedef int F(int);");
+ analyze('(F f) => f.toString;');
+ analyze('(F f) => f.toString();');
+ analyze('(F f) => f.foo;', MEMBER_NOT_FOUND);
+ analyze('(F f) => f.foo();', MessageKind.METHOD_NOT_FOUND);
+}
+
void testTypeLiteral() {
final String source = r"""class Class {
static var field = null;
diff --git a/tests/compiler/dart2js_native/oddly_named_fields_test.dart b/tests/compiler/dart2js_native/oddly_named_fields_test.dart
index 6ade208..b2dae29 100644
--- a/tests/compiler/dart2js_native/oddly_named_fields_test.dart
+++ b/tests/compiler/dart2js_native/oddly_named_fields_test.dart
@@ -1369,7 +1369,7 @@
if (object.yieldValue) throw 'incorrect value in "yieldValue"';
}
-makeNativeClassWithOddNames() native;
+NativeClassWithOddNames makeNativeClassWithOddNames() native;
setup() native """
function NativeClassWithOddNames() {}
@@ -1378,7 +1378,7 @@
main() {
setup();
- var object = new NativeClassWithOddNames();
+ var object = makeNativeClassWithOddNames();
object.testMyFields();
testObjectStronglyTyped(object);
testObjectWeaklyTyped([object]);
diff --git a/tests/compiler/dart2js_native/subclassing_constructor_1_test.dart b/tests/compiler/dart2js_native/subclassing_constructor_1_test.dart
new file mode 100644
index 0000000..333a9f2
--- /dev/null
+++ b/tests/compiler/dart2js_native/subclassing_constructor_1_test.dart
@@ -0,0 +1,176 @@
+// 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 "package:expect/expect.dart";
+import 'dart:_foreign_helper' show JS;
+import 'dart:_js_helper' show Creates, setNativeSubclassDispatchRecord;
+import 'dart:_interceptors' show
+ findInterceptorForType, findConstructorForWebComponentType;
+
+// Test that subclasses of native classes can be initialized by calling the
+// 'upgrade' constructor.
+
+var trace = [];
+
+var log;
+
+class A native "A" {
+ final a1 = log(101); // Only initialized IF named constructor called.
+ final a2; // Initialized by native constructor.
+ final a3; // Initialized only by A.two.
+ var a4 = log(104);
+
+ A.one();
+
+ A.two() : a3 = log(103) {
+ log('body(A.two)');
+ log(a4 += increment);
+ }
+
+ A.three(x, this.a4) {
+ log('body(A.three)');
+ log(a4 = '($a4, $x)');
+ }
+
+ get increment => 10;
+}
+
+class B extends A {
+ final b1;
+ final b2 = log(202);
+ var b3;
+
+ B.one() : super.one();
+
+ B.two() : b1 = log(201), super.two(), b3 = log(203) {
+ log('body(B.two)');
+ }
+
+ B.three([x]) : super.three(205, x);
+
+ get increment => 20;
+}
+
+
+makeB() native;
+
+@Creates('=Object')
+getBPrototype() native;
+
+void setup() native r"""
+function B() { this.a2 = 102; }
+
+makeB = function(){return new B;};
+
+getBPrototype = function(){return B.prototype;};
+""";
+
+
+test_one() {
+ trace = [];
+ var constructor = findConstructorForWebComponentType(B, 'one');
+ Expect.isNotNull(constructor);
+ Expect.isNull(findConstructorForWebComponentType(B, 'Missing'));
+
+ var b = makeB();
+ Expect.isTrue(b is B);
+ // Call constructor to initialize native object.
+ var b2 = JS('', '#(#)', constructor, b);
+ Expect.identical(b, b2);
+ Expect.isTrue(b is B);
+
+ Expect.equals(101, b.a1);
+ Expect.equals(102, b.a2);
+ Expect.equals(null, b.a3);
+ Expect.equals(104, b.a4);
+ Expect.equals(null, b.b1);
+ Expect.equals(202, b.b2);
+ Expect.equals(null, b.b3);
+
+ Expect.equals('[202, 101, 104]', '$trace');
+}
+
+test_two() {
+ trace = [];
+ var constructor = findConstructorForWebComponentType(B, 'two');
+ Expect.isNotNull(constructor);
+
+ var b = makeB();
+ Expect.isTrue(b is B);
+ // Call constructor to initialize native object.
+ JS('', '#(#)', constructor, b);
+ Expect.isTrue(b is B);
+
+ Expect.equals(101, b.a1);
+ Expect.equals(102, b.a2);
+ Expect.equals(103, b.a3);
+ Expect.equals(124, b.a4);
+ Expect.equals(201, b.b1);
+ Expect.equals(202, b.b2);
+ Expect.equals(203, b.b3);
+
+ Expect.equals(
+ '[202, 201, 101, 104, 103, 203, body(A.two), 124, body(B.two)]',
+ '$trace');
+}
+
+test_three() {
+ trace = [];
+ var constructor = findConstructorForWebComponentType(B, 'three');
+ Expect.isNotNull(constructor);
+
+ var b = makeB();
+ Expect.isTrue(b is B);
+ // Call constructor to initialize native object.
+ //
+ // Since the constructor takes some optional arguments that are not passed, it
+ // is as though the web components runtime explicitly passed `null` for all
+ // parameters.
+ //
+ // TODO(sra): The constructor returned by findConstructorForWebComponentType
+ // should be a function that fills in the default values.
+ JS('', '#(#)', constructor, b);
+ Expect.isTrue(b is B);
+
+ Expect.equals(101, b.a1);
+ Expect.equals(102, b.a2);
+ Expect.equals(null, b.a3);
+ Expect.equals('(null, 205)', b.a4);
+ Expect.equals(null, b.b1);
+ Expect.equals(202, b.b2);
+ Expect.equals(null, b.b3);
+ print(trace);
+ Expect.equals('[202, 101, 104, body(A.three), (null, 205)]', '$trace');
+}
+
+test_new() {
+ trace = [];
+ checkThrows(action, description) {
+ Expect.throws(action, (e) => true, "'$description must fail'");
+ }
+
+ checkThrows(() => new B.one(), 'new B.one()');
+ checkThrows(() => new B.two(), 'new B.two()');
+ checkThrows(() => new B.three(), 'new B.three()');
+ checkThrows(() => new B.three(1), 'new B.three(1)');
+ checkThrows(() => new B.three([]), 'new B.three([])');
+}
+
+var inscrutable;
+
+main() {
+ setup();
+ inscrutable = (x) => x;
+ log = (message) {
+ trace.add('$message');
+ return message;
+ };
+
+ setNativeSubclassDispatchRecord(getBPrototype(), findInterceptorForType(B));
+
+ test_one();
+ test_two();
+ test_three();
+ test_new();
+}
diff --git a/tests/corelib/corelib.status b/tests/corelib/corelib.status
index 7902d5a..61892e6 100644
--- a/tests/corelib/corelib.status
+++ b/tests/corelib/corelib.status
@@ -48,6 +48,7 @@
date_time7_test: Fail # BUG(3304): Maybe this doesn't time out?
string_base_vm_test: Fail # BUG(3304): Maybe this doesn't time out?
list_test: Fail # IE doesn't support typed data.
+shuffle_test: Fail # IE doesn't support typed data.
[ $compiler == dart2js && $runtime == chromeOnAndroid ]
list_as_map_test: Pass, Slow # TODO(kasperl): Please triage.
diff --git a/tests/corelib/hashcode_boxed_test.dart b/tests/corelib/hashcode_boxed_test.dart
new file mode 100644
index 0000000..6b1d44c
--- /dev/null
+++ b/tests/corelib/hashcode_boxed_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.
+
+import "package:expect/expect.dart";
+
+double fib(double n) {
+ return n <= 1.0 ? 1.0 : fib(n-1) + fib(n-2);
+}
+
+main() {
+ // Compute the same value in a way that won't be optimized away so the results
+ // are different objects in memory.
+ var a = fib(5.0) + 1.0;
+ var b = fib(4.0) + 4.0;
+
+ Expect.isTrue(identical(a, b));
+ Expect.equals(identityHashCode(a), identityHashCode(b));
+ Expect.equals(a, b);
+ Expect.equals(a.hashCode, b.hashCode);
+}
diff --git a/tests/corelib/shuffle_test.dart b/tests/corelib/shuffle_test.dart
new file mode 100644
index 0000000..786dc91
--- /dev/null
+++ b/tests/corelib/shuffle_test.dart
@@ -0,0 +1,92 @@
+// Copyright (c) 2011, 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 for List.shuffle.
+library shuffle_test;
+import "dart:typed_data";
+import "package:expect/expect.dart";
+
+main() {
+ List mkList(int n) => new List.generate(n, (x) => x);
+
+ for (int size in [0, 1, 2, 3, 7, 15, 99, 1023]) {
+ List numbers = new List.generate(size, (x) => x);
+ testShuffle(numbers.toList(growable: true));
+ testShuffle(numbers.toList(growable: false));
+ testShuffle(new Uint32List(size)..setAll(0, numbers));
+ testShuffle(new Int32List(size)..setAll(0, numbers));
+ testShuffle(new Uint16List(size)..setAll(0, numbers));
+ testShuffle(new Int16List(size)..setAll(0, numbers));
+ // Some numbers will be truncated in the following two.
+ testShuffle(new Uint8List(size)..setAll(0, numbers));
+ testShuffle(new Int8List(size)..setAll(0, numbers));
+ testShuffle(numbers.map((x) => "$x").toList());
+ }
+
+ // Check that it actually can keep the same list (regression test).
+ List l = [1, 2];
+ success: {
+ for (int i = 0; i < 266; i++) {
+ int first = l.first;
+ l.shuffle();
+ if (l.first == first) break success; // List didn't change.
+ }
+ // Chance of changing 266 times in a row should be < 1:1e80.
+ Expect.fail("List changes every time.");
+ }
+}
+
+void testShuffle(list) {
+ List copy = list.toList();
+ list.shuffle();
+ if (list.length < 2) {
+ Expect.listEquals(copy, list);
+ return;
+ }
+ // Test that the list after shuffling has the same elements as before,
+ // without considering order.
+ Map seen = {};
+ for (var e in list) {
+ seen[e] = seen.putIfAbsent(e, () => 0) + 1;
+ }
+ for (var e in copy) {
+ int remaining = seen[e];
+ remaining -= 1; // Throws if e was not in map at all.
+ if (remaining == 0) {
+ seen.remove(e);
+ } else {
+ seen[e] = remaining;
+ }
+ }
+ Expect.isTrue(seen.isEmpty);
+ // Test that shuffle actually does make a change. Repeat until the probability
+ // of a proper shuffling hitting the same list again is less than 10^80
+ // (arbitrary bignum - approx. number of elemental particles in the universe).
+ //
+ // The probablility of shuffling a list of length n into the same list is
+ // 1/n!. If one shuffle didn't change the list, repeat shuffling until
+ // probability of randomly hitting the same list every time is less than
+ // 1/1e80.
+
+ bool listsDifferent() {
+ for (int i = 0; i < list.length; i++) {
+ if (list[i] != copy[i]) return true;
+ }
+ return false;
+ }
+ if (list.length < 59) { // 59! > 1e80.
+ double limit = 1e80;
+ double fact = 1.0;
+ for (int i = 2; i < list.length; i++) fact *= i;
+ double combos = fact;
+
+ while (!listsDifferent() && combos < limit) {
+ list.shuffle();
+ combos *= fact;
+ }
+ }
+ if (!listsDifferent()) {
+ Expect.fail("Didn't shuffle at all, p < 1:1e80: $list");
+ }
+}
diff --git a/tests/html/canvasrenderingcontext2d_test.dart b/tests/html/canvasrenderingcontext2d_test.dart
index b10756f..da9338b 100644
--- a/tests/html/canvasrenderingcontext2d_test.dart
+++ b/tests/html/canvasrenderingcontext2d_test.dart
@@ -363,7 +363,7 @@
var img = new ImageElement();
img.onLoad.listen(expectAsync1((_) {
- context.drawImageToRect(img, new Rect(50, 50, 20, 20));
+ context.drawImageToRect(img, new Rectangle(50, 50, 20, 20));
expectPixelFilled(50, 50);
expectPixelFilled(55, 55);
@@ -393,8 +393,8 @@
// This will take a 6x6 square from the first canvas from position 2,2
// and then scale it to a 20x20 square and place it to the second
// canvas at 50,50.
- context.drawImageToRect(img, new Rect(50, 50, 20, 20),
- sourceRect: new Rect(2, 2, 6, 6));
+ context.drawImageToRect(img, new Rectangle(50, 50, 20, 20),
+ sourceRect: new Rectangle(2, 2, 6, 6));
checkPixel(readPixel(50, 50), [255, 0, 0, 255]);
checkPixel(readPixel(55, 55), [255, 0, 0, 255]);
@@ -511,7 +511,7 @@
test('with 5 params', () {
video.onCanPlay.listen(expectAsync1((_) {
- context.drawImageToRect(video, new Rect(50, 50, 20, 20));
+ context.drawImageToRect(video, new Rectangle(50, 50, 20, 20));
expectPixelFilled(50, 50);
expectPixelFilled(55, 55);
@@ -541,8 +541,8 @@
test('with 9 params', () {
video.onCanPlay.listen(expectAsync1((_) {
- context.drawImageToRect(video, new Rect(50, 50, 20, 20),
- sourceRect: new Rect(2, 2, 6, 6));
+ context.drawImageToRect(video, new Rectangle(50, 50, 20, 20),
+ sourceRect: new Rectangle(2, 2, 6, 6));
expectPixelFilled(50, 50);
expectPixelFilled(55, 55);
@@ -579,8 +579,8 @@
video = new VideoElement();
canvas = new CanvasElement();
video.onCanPlay.listen(expectAsync1((_) {
- context.drawImageToRect(video, new Rect(50, 50, 20, 20),
- sourceRect: new Rect(2, 2, 6, 6));
+ context.drawImageToRect(video, new Rectangle(50, 50, 20, 20),
+ sourceRect: new Rectangle(2, 2, 6, 6));
expectPixelFilled(50, 50);
expectPixelFilled(55, 55);
@@ -626,7 +626,7 @@
});
test('with 5 params', () {
// Draw an image to the canvas from a canvas element.
- context.drawImageToRect(otherCanvas, new Rect(50, 50, 20, 20));
+ context.drawImageToRect(otherCanvas, new Rectangle(50, 50, 20, 20));
expectPixelFilled(50, 50);
expectPixelFilled(55, 55);
@@ -641,8 +641,8 @@
// Draw an image to the canvas from a canvas element.
otherContext.fillStyle = "blue";
otherContext.fillRect(5, 5, 5, 5);
- context.drawImageToRect(otherCanvas, new Rect(50, 50, 20, 20),
- sourceRect: new Rect(2, 2, 6, 6));
+ context.drawImageToRect(otherCanvas, new Rectangle(50, 50, 20, 20),
+ sourceRect: new Rectangle(2, 2, 6, 6));
checkPixel(readPixel(50, 50), [255, 0, 0, 255]);
checkPixel(readPixel(55, 55), [255, 0, 0, 255]);
diff --git a/tests/html/client_rect_test.dart b/tests/html/client_rect_test.dart
index 76751da..9bc233f 100644
--- a/tests/html/client_rect_test.dart
+++ b/tests/html/client_rect_test.dart
@@ -6,7 +6,7 @@
main() {
var isRectList =
- predicate((x) => x is List<Rect>, 'is a List<Rect>');
+ predicate((x) => x is List<Rectangle>, 'is a List<Rectangle>');
insertTestDiv() {
var element = new Element.tag('div');
diff --git a/tests/html/custom/attribute_changed_callback_test.dart b/tests/html/custom/attribute_changed_callback_test.dart
index 3a9271a..1bcc453 100644
--- a/tests/html/custom/attribute_changed_callback_test.dart
+++ b/tests/html/custom/attribute_changed_callback_test.dart
@@ -92,6 +92,8 @@
group('unsupported_on_polyfill', () {
test('add, change ID', () {
+ B.invocations = [];
+
var b = new B();
b.id = 'x';
expect(B.invocations, ['created', 'id: null => x']);
diff --git a/tests/html/custom/entered_left_view_test.dart b/tests/html/custom/entered_left_view_test.dart
index a523854..19899ff 100644
--- a/tests/html/custom/entered_left_view_test.dart
+++ b/tests/html/custom/entered_left_view_test.dart
@@ -127,14 +127,13 @@
'document without a view');
});
- /*
test('Attribute changed in document without a view', () {
a.setAttribute('data-foo', 'bar');
expect(invocations, ['attribute changed'],
reason: 'changing an attribute should invoke the callback, even in a '
'document without a view');
});
- */
+
test('Entered document with a view', () {
document.body.append(a);
customElementsTakeRecords();
diff --git a/tests/html/element_test.dart b/tests/html/element_test.dart
index 42015fd..58b0fe0 100644
--- a/tests/html/element_test.dart
+++ b/tests/html/element_test.dart
@@ -10,7 +10,7 @@
import 'dart:svg' as svg;
import 'utils.dart';
-expectLargeRect(Rect rect) {
+expectLargeRect(Rectangle rect) {
expect(rect.top, 0);
expect(rect.left, 0);
expect(rect.width, greaterThan(100));
diff --git a/tests/html/html.status b/tests/html/html.status
index 5db1caa..cfc5b61 100644
--- a/tests/html/html.status
+++ b/tests/html/html.status
@@ -28,7 +28,6 @@
# postMessage in dartium always transfers the typed array buffer, never a view
postmessage_structured_test/typed_arrays: Fail
xhr_test: Pass, Fail # Issue 12648
-custom/attribute_changed_callback_test: Fail # 12643
xhr_test/json: Fail # Issue 13069
uri_test: Fail Issue 13581
async_test: Fail # Background timers not implemented.
@@ -404,3 +403,25 @@
[ $compiler == dart2js && $runtime == drt ]
wheelevent_test: Fail # http://dartbug.com/12958
+
+[ $compiler == none && $runtime == dartium ]
+async_test: Timeout # Issue 13719: Please triage this failure.
+custom/attribute_changed_callback_test/fully_supported: Fail # Issue 13719: Please triage this failure.
+custom/attribute_changed_callback_test/unsupported_on_polyfill: Fail # Issue 13719: Please triage this failure.
+custom/constructor_calls_created_synchronously_test: Fail # Issue 13719: Please triage this failure.
+custom/created_callback_test: Fail # Issue 13719: Please triage this failure.
+custom/document_register_basic_test: Fail # Issue 13719: Please triage this failure.
+custom/document_register_type_extensions_test/construction: Fail # Issue 13719: Please triage this failure.
+custom/document_register_type_extensions_test/namespaces: Fail # Issue 13719: Please triage this failure.
+custom/document_register_type_extensions_test/parsing: Fail # Issue 13719: Please triage this failure.
+custom_elements_test/innerHtml: Fail # Issue 13719: Please triage this failure.
+custom_elements_test/lifecycle: Fail # Issue 13719: Please triage this failure.
+custom_elements_test/mixins: Fail # Issue 13719: Please triage this failure.
+custom_elements_test/register: Fail # Issue 13719: Please triage this failure.
+custom/entered_left_view_test/disconnected_subtree: Fail # Issue 13719: Please triage this failure.
+custom/entered_left_view_test/shadow_dom: Fail # Issue 13719: Please triage this failure.
+custom/entered_left_view_test/standard_events: Fail # Issue 13719: Please triage this failure.
+custom/entered_left_view_test/viewless_document: Fail # Issue 13719: Please triage this failure.
+dromaeo_smoke_test: Fail # Issue 13719: Please triage this failure.
+element_offset_test/offset: Fail # Issue 13719: Please triage this failure.
+touchevent_test/supported: Fail # Issue 13719: Please triage this failure.
diff --git a/tests/html/rect_test.dart b/tests/html/rect_test.dart
deleted file mode 100644
index 8b52f61..0000000
--- a/tests/html/rect_test.dart
+++ /dev/null
@@ -1,159 +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.
-
-library rect_test;
-
-import 'dart:html';
-import '../../pkg/unittest/lib/unittest.dart';
-import '../../pkg/unittest/lib/html_config.dart';
-
-main() {
- useHtmlConfiguration();
-
- Rect createRect(List<num> a) {
- return a != null ? new Rect(a[0], a[1], a[2] - a[0], a[3] - a[1]) : null;
- }
-
- test('construction', () {
- var r0 = new Rect(10, 20, 30, 40);
- expect(r0.toString(), '(10, 20, 30, 40)');
- expect(r0.right, 40);
- expect(r0.bottom, 60);
-
- var r1 = new Rect.fromPoints(r0.topLeft, r0.bottomRight);
- expect(r1, r0);
-
- var r2 = new Rect.fromPoints(r0.bottomRight, r0.topLeft);
- expect(r2, r0);
- });
-
- test('intersection', () {
- var tests = [
- [[10, 10, 20, 20], [15, 15, 25, 25], [15, 15, 20, 20]],
- [[10, 10, 20, 20], [20, 0, 30, 10], [20, 10, 20, 10]],
- [[0, 0, 1, 1], [10, 11, 12, 13], null],
- [[11, 12, 98, 99], [22, 23, 34, 35], [22, 23, 34, 35]]];
-
- for (var test in tests) {
- var r0 = createRect(test[0]);
- var r1 = createRect(test[1]);
- var expected = createRect(test[2]);
-
- expect(r0.intersection(r1), expected);
- expect(r1.intersection(r0), expected);
- }
- });
-
- test('intersects', () {
- var r0 = new Rect(10, 10, 20, 20);
- var r1 = new Rect(15, 15, 25, 25);
- var r2 = new Rect(0, 0, 1, 1);
-
- expect(r0.intersects(r1), isTrue);
- expect(r1.intersects(r0), isTrue);
-
- expect(r0.intersects(r2), isFalse);
- expect(r2.intersects(r0), isFalse);
- });
-
- test('union', () {
- var tests = [
- [[10, 10, 20, 20], [15, 15, 25, 25], [10, 10, 25, 25]],
- [[10, 10, 20, 20], [20, 0, 30, 10], [10, 0, 30, 20]],
- [[0, 0, 1, 1], [10, 11, 12, 13], [0, 0, 12, 13]],
- [[11, 12, 98, 99], [22, 23, 34, 35], [11, 12, 98, 99]]];
-
- for (var test in tests) {
- var r0 = createRect(test[0]);
- var r1 = createRect(test[1]);
- var expected = createRect(test[2]);
-
- expect(r0.union(r1), expected);
- expect(r1.union(r0), expected);
- }
- });
-
- test('containsRect', () {
- var r = new Rect(-10, 0, 20, 10);
- expect(r.containsRect(r), isTrue);
-
- expect(r.containsRect(
- new Rect(double.NAN, double.NAN, double.NAN, double.NAN)), isFalse);
-
- var r2 = new Rect(0, 2, 5, 5);
- expect(r.containsRect(r2), isTrue);
- expect(r2.containsRect(r), isFalse);
-
- r2 = new Rect(-11, 2, 5, 5);
- expect(r.containsRect(r2), isFalse);
- r2 = new Rect(0, 2, 15, 5);
- expect(r.containsRect(r2), isFalse);
- r2 = new Rect(0, 2, 5, 10);
- expect(r.containsRect(r2), isFalse);
- r2 = new Rect(0, 0, 5, 10);
- expect(r.containsRect(r2), isTrue);
- });
-
- test('containsPoint', () {
- var r = new Rect(20, 40, 60, 80);
-
- // Test middle.
- expect(r.containsPoint(new Point(50, 80)), isTrue);
-
- // Test edges.
- expect(r.containsPoint(new Point(20, 40)), isTrue);
- expect(r.containsPoint(new Point(50, 40)), isTrue);
- expect(r.containsPoint(new Point(80, 40)), isTrue);
- expect(r.containsPoint(new Point(80, 80)), isTrue);
- expect(r.containsPoint(new Point(80, 120)), isTrue);
- expect(r.containsPoint(new Point(50, 120)), isTrue);
- expect(r.containsPoint(new Point(20, 120)), isTrue);
- expect(r.containsPoint(new Point(20, 80)), isTrue);
-
- // Test outside.
- expect(r.containsPoint(new Point(0, 0)), isFalse);
- expect(r.containsPoint(new Point(50, 0)), isFalse);
- expect(r.containsPoint(new Point(100, 0)), isFalse);
- expect(r.containsPoint(new Point(100, 80)), isFalse);
- expect(r.containsPoint(new Point(100, 160)), isFalse);
- expect(r.containsPoint(new Point(50, 160)), isFalse);
- expect(r.containsPoint(new Point(0, 160)), isFalse);
- expect(r.containsPoint(new Point(0, 80)), isFalse);
- });
-
- test('ceil', () {
- var rect = new Rect(11.4, 26.6, 17.8, 9.2);
- expect(rect.ceil(), new Rect(12.0, 27.0, 18.0, 10.0));
- });
-
- test('floor', () {
- var rect = new Rect(11.4, 26.6, 17.8, 9.2);
- expect(rect.floor(), new Rect(11.0, 26.0, 17.0, 9.0));
- });
-
- test('round', () {
- var rect = new Rect(11.4, 26.6, 17.8, 9.2);
- expect(rect.round(), new Rect(11.0, 27.0, 18.0, 9.0));
- });
-
- test('toInt', () {
- var rect = new Rect(11.4, 26.6, 17.8, 9.2);
- var b = rect.toInt();
- expect(b, new Rect(11, 26, 17, 9));
-
- expect(b.left is int, isTrue);
- expect(b.top is int, isTrue);
- expect(b.width is int, isTrue);
- expect(b.height is int, isTrue);
- });
-
- test('hashCode', () {
- var a = new Rect(0, 1, 2, 3);
- var b = new Rect(0, 1, 2, 3);
- expect(a.hashCode, b.hashCode);
-
- var c = new Rect(1, 0, 2, 3);
- expect(a.hashCode == c.hashCode, isFalse);
- });
-}
diff --git a/tests/html/svgelement_test.dart b/tests/html/svgelement_test.dart
index 1dad882..7ab3d5138 100644
--- a/tests/html/svgelement_test.dart
+++ b/tests/html/svgelement_test.dart
@@ -426,7 +426,7 @@
});
group('getBoundingClientRect', () {
- test('is a Rect', () {
+ test('is a Rectangle', () {
var element = new svg.RectElement();
element.attributes['width'] = '100';
element.attributes['height'] = '100';
@@ -436,7 +436,7 @@
document.body.append(root);
var rect = element.getBoundingClientRect();
- expect(rect is Rect, isTrue);
+ expect(rect is Rectangle, isTrue);
expect(rect.width, closeTo(100, 1));
expect(rect.height, closeTo(100, 1));
});
diff --git a/tests/isolate/isolate.status b/tests/isolate/isolate.status
index a74948a..50b8d2a 100644
--- a/tests/isolate/isolate.status
+++ b/tests/isolate/isolate.status
@@ -103,4 +103,8 @@
spawn_uri_multi_test/none: RuntimeError # http://dartbug.com/13544
[ $compiler == none && $runtime == dartium ]
+cross_isolate_message_stream_test: Fail # Issue 13719: Please triage this failure.
global_error_handler2_test: Fail # Issue 13719: Please triage this failure.
+global_error_handler_stream2_test: Fail # Issue 13719: Please triage this failure.
+nested_spawn_stream2_test: Fail # Issue 13719: Please triage this failure.
+
diff --git a/tests/language/compile_time_constant_test.dart b/tests/language/compile_time_constant_test.dart
index 53e9198..ae3333d 100644
--- a/tests/language/compile_time_constant_test.dart
+++ b/tests/language/compile_time_constant_test.dart
@@ -4,7 +4,7 @@
class Bad {
int foo;
- const int bar =
+ final int bar =
foo /// 01: compile-time error
-1;
static const int toto =
diff --git a/tests/language/const_escape_frog_test.dart b/tests/language/const_escape_frog_test.dart
index ea39cc3..1cb6cd2 100644
--- a/tests/language/const_escape_frog_test.dart
+++ b/tests/language/const_escape_frog_test.dart
@@ -7,7 +7,7 @@
import "package:expect/expect.dart";
class Foo {
- const Bar<Foo> bar = const Bar/* comment here use to trigger bug 323 */();
+ final Bar<Foo> bar = const Bar/* comment here use to trigger bug 323 */();
}
class Bar<T extends Foo> {
diff --git a/tests/language/duplicate_export_liba.dart b/tests/language/duplicate_export_liba.dart
new file mode 100644
index 0000000..7b68d42
--- /dev/null
+++ b/tests/language/duplicate_export_liba.dart
@@ -0,0 +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.
+
+library export_liba;
+
+export 'duplicate_import_liba.dart';
diff --git a/tests/language/duplicate_export_test.dart b/tests/language/duplicate_export_test.dart
new file mode 100644
index 0000000..239de6a
--- /dev/null
+++ b/tests/language/duplicate_export_test.dart
@@ -0,0 +1,14 @@
+// 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 it is not a compile-time error to reexport the same elements
+// through different paths.
+
+library duplicate_export_test;
+
+export 'duplicate_import_liba.dart';
+export 'duplicate_export_liba.dart'; // reexports 'duplicate_import_liba.dart'.
+
+void main() {
+}
\ No newline at end of file
diff --git a/tests/language/issue13474_test.dart b/tests/language/issue13474_test.dart
new file mode 100644
index 0000000..f35f5b6
--- /dev/null
+++ b/tests/language/issue13474_test.dart
@@ -0,0 +1,20 @@
+// 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=--enable_type_checks
+
+import "package:expect/expect.dart";
+
+main() {
+ var a;
+ Expect.throws(() { true && (a = 5); }, (error) => error is TypeError);
+ Expect.throws(() { (a = 5) && true; }, (error) => error is TypeError);
+ Expect.throws(() { false || (a = 5); }, (error) => error is TypeError);
+ Expect.throws(() { (a = 5) || false; }, (error) => error is TypeError);
+ Expect.throws(() { (a = 5) || true; }, (error) => error is TypeError);
+
+ // No exceptions thrown.
+ false && (a = 5);
+ true || (a = 5);
+}
+
diff --git a/tests/language/language.status b/tests/language/language.status
index bd6e7e2..bc2c98c 100644
--- a/tests/language/language.status
+++ b/tests/language/language.status
@@ -55,6 +55,7 @@
compile_time_constant_checked3_test/06: Fail, OK
[ $runtime == vm || ($runtime == drt && $compiler == none) ]
+regress_13494_test: Fail # Issue 13494
first_class_types_literals_test: Fail # issue 11761
call_test: Fail # Issue 12602
dynamic_prefix_core_test: Fail # Issue 12478
@@ -86,3 +87,7 @@
positional_parameters_type_test/02: Fail # Issue 13719: Please triage this failure.
type_checks_in_factory_method_test: Fail # Issue 13719: Please triage this failure.
vm/type_vm_test: Fail # Issue 13719: Please triage this failure.
+
+
+[ $compiler == none && $runtime == dartium ]
+regress_13494_test: Fail # Issue 13719: Please triage this failure.
diff --git a/tests/language/language_analyzer.status b/tests/language/language_analyzer.status
index 536168e..34ee194 100644
--- a/tests/language/language_analyzer.status
+++ b/tests/language/language_analyzer.status
@@ -64,10 +64,6 @@
final_syntax_test/02: Fail # Issue 11124
final_syntax_test/03: Fail # Issue 11124
-# Test issue 11123, Only static fields can be declared as 'const'
-const_escape_frog_test: fail
-compile_time_constant_test/none: fail
-
# Test issue 11545, using not existing constructor name in annotation
metadata_test: fail
@@ -189,6 +185,9 @@
static_field_test/03: fail # Issue 12541
static_field_test/04: fail # Issue 12541
+# test issue 13787; duplicate exports of the same declaration is not handled
+duplicate_export_test: fail # Issue 13787
+
[ $compiler == dartanalyzer && $checked ]
factory1_test/00: fail
factory1_test/01: fail
diff --git a/tests/language/language_analyzer2.status b/tests/language/language_analyzer2.status
index 17a459a..1bb5a27 100644
--- a/tests/language/language_analyzer2.status
+++ b/tests/language/language_analyzer2.status
@@ -75,10 +75,6 @@
final_syntax_test/02: Fail # Issue 11124
final_syntax_test/03: Fail # Issue 11124
-# Test issue 11123, Only static fields can be declared as 'const'
-const_escape_frog_test: fail
-compile_time_constant_test/none: fail
-
# Test issue 11545, using not existing constructor name in annotation
metadata_test: fail
@@ -200,6 +196,9 @@
static_field_test/03: fail # Issue 12541
static_field_test/04: fail # Issue 12541
+# test issue 13787; duplicate exports of the same declaration is not handled
+duplicate_export_test: fail # Issue 13787
+
[ $compiler == dart2analyzer && $checked ]
factory1_test/00: fail
factory1_test/01: fail
diff --git a/tests/language/language_dart2js.status b/tests/language/language_dart2js.status
index 87857b1..1c1f692 100644
--- a/tests/language/language_dart2js.status
+++ b/tests/language/language_dart2js.status
@@ -66,6 +66,7 @@
named_parameters_type_test/03: MissingRuntimeError, OK
positional_parameters_type_test/01: MissingRuntimeError, OK
positional_parameters_type_test/02: MissingRuntimeError, OK
+issue13474_test: RuntimeError, OK
[ $compiler == dart2js && $minified ]
f_bounded_quantification4_test: Fail # Issue 12605.
@@ -156,11 +157,6 @@
bit_operations_test: RuntimeError, OK # Issue 1533
expect_test: RuntimeError, OK # Issue 13080
-final_syntax_test/01: MissingCompileTimeError # Issue 13020
-final_syntax_test/02: MissingCompileTimeError # Issue 13020
-final_syntax_test/03: MissingCompileTimeError # Issue 13020
-final_syntax_test/04: MissingCompileTimeError # Issue 13020
-
null_test/none: RuntimeError # Issue 12482
@@ -244,10 +240,6 @@
constructor9_test/01: Fail # Issue 12935
constructor_named_arguments_test/01: Fail # Issue 5519
-final_syntax_test/01: Fail # Issue 13020
-final_syntax_test/02: Fail # Issue 13020
-final_syntax_test/03: Fail # Issue 13020
-final_syntax_test/04: Fail # Issue 13020
named_parameters_aggregated_test/03: Fail # Issue 12813
not_enough_positional_arguments_test/01: Fail # Issue 12839
not_enough_positional_arguments_test/02: Fail # Issue 12839
diff --git a/tests/language/regress_13494_test.dart b/tests/language/regress_13494_test.dart
new file mode 100644
index 0000000..aaf975a
--- /dev/null
+++ b/tests/language/regress_13494_test.dart
@@ -0,0 +1,25 @@
+// 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.
+
+// Regression test for dart2js. Test that the argument to an unresolved static
+// getter is only evaluated once.
+
+import "package:expect/expect.dart";
+
+int i = 0;
+
+p(x) => i++;
+
+class A {}
+
+main() {
+ bool caught = false;
+ try {
+ A.unknown = p(2);
+ } catch (_) {
+ caught = true;
+ }
+ Expect.isTrue(caught);
+ Expect.equals(1, i);
+}
diff --git a/tests/lib/lib.status b/tests/lib/lib.status
index 61ba7ee..763dde2 100644
--- a/tests/lib/lib.status
+++ b/tests/lib/lib.status
@@ -7,11 +7,16 @@
math/low_test: RuntimeError
math/random_test: RuntimeError
mirrors/closure_mirror_find_in_context_test: Fail # Issue 6490
+mirrors/constructor_kinds_test: RuntimeError # Issue 13799
mirrors/equality_test/02: RuntimeError # Issue 12333
mirrors/fake_function_test: RuntimeError # Issue 11612
mirrors/function_type_mirror_test: RuntimeError # Issue 12166
-mirrors/generics_test/01: RuntimeError # Issue 12333
+mirrors/generics_test/01: RuntimeError # Issue 12087
+mirrors/generic_function_typedef_test: RuntimeError # Issue 12333
+mirrors/generic_mixin_applications_test: RuntimeError # Issue 12333
+mirrors/generics_substitution_test: RuntimeError # Issue 12087
mirrors/hierarchy_invariants_test: RuntimeError # Issue 11863
+mirrors/initializing_formals_test: CompileTimeError # Issue 12164
mirrors/invoke_test: RuntimeError # Issue 11954
mirrors/invoke_closurization_test: RuntimeError # Issue 13002
mirrors/invoke_named_test/none: RuntimeError # Issue 12863
@@ -29,6 +34,7 @@
mirrors/parameter_test/none: RuntimeError # Issue 6490
mirrors/parameter_metadata_test: CompileTimeError # Issue 10905
mirrors/reflected_type_test: RuntimeError # Issue 12607
+mirrors/type_argument_is_type_variable_test: RuntimeError # Issue 12333
mirrors/typedef_metadata_test: RuntimeError # Issue 12785
mirrors/typevariable_mirror_metadata_test: CompileTimeError # Issue 10905
mirrors/unnamed_library_test: RuntimeError # Issue 10580
@@ -120,6 +126,7 @@
convert/streamed_conversion_json_utf8_decode_test: Pass, Timeout # Issue 12029
async/deferred/deferred_api_test: Pass, Timeout # http://dartbug.com/12635
convert/streamed_conversion_utf8_decode_test: Pass, Timeout # http://dartbug.com/12768
+convert/utf85_test: Skip # Issue 12029.
[ $compiler == dart2js ]
typed_data/typed_data_hierarchy_int64_test: RuntimeError # Issue 10275
@@ -144,6 +151,13 @@
mirrors/typedef_test/01: Fail, OK # Incorrect dart2js behavior.
mirrors/closures_test/01: Fail, OK # Incorrect dart2js behavior.
+mirrors/constructor_kinds_test: RuntimeError # Issue 13798
+mirrors/generics_substitution_test: RuntimeError # Issue 13808
+mirrors/initializing_formals_test/01: RuntimeError # Issue 11281
+mirrors/generic_function_typedef_test: RuntimeError # Issue 12282
+mirrors/generic_mixin_applications_test: RuntimeError # Issue 12282
+mirrors/type_argument_is_type_variable_test: RuntimeError # Issue 12282
+
[ $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
@@ -162,6 +176,7 @@
[ $arch == simarm ]
convert/chunked_conversion_utf88_test: Pass, Slow # Issue 12644.
+convert/utf85_test: Pass, Slow # Issue 12644.
[ $compiler == none && $runtime == drt ]
async/run_zoned6_test/01: fail # Issue 12756.
@@ -174,11 +189,6 @@
mirrors/generics_test/none: Fail # Issue 13432
mirrors/invoke_named_test/none: Fail # http://dartbug.com/13612
-mirrors/parameter_metadata_test: Fail # Issue 13510
-mirrors/method_mirror_returntype_test: Fail # Issue 13510
-mirrors/function_type_mirror_test: Fail # Issue 13510
-mirrors/typevariable_mirror_metadata_test: Fail # Issue 13510
-
[ $compiler == dart2analyzer ]
mirrors/typedef_test/none: Fail # Issue 13093
mirrors/generics_test/none: Fail # Issue 13432
@@ -200,3 +210,7 @@
mirrors/local_isolate_test: Fail # Issue 13719: Please triage this failure.
mirrors/mixin_test/01: Fail # Issue 13719: Please triage this failure.
mirrors/typedef_test/01: Fail # Issue 13719: Please triage this failure.
+
+[ $compiler == none && $runtime == dartium ]
+async/timer_isolate_test: Fail # Issue 13719: Please triage this failure.
+async/run_async5_test: Pass, Timeout # Issue 13719: Please triage this failure.
diff --git a/tests/html/point_test.dart b/tests/lib/math/point_test.dart
similarity index 61%
rename from tests/html/point_test.dart
rename to tests/lib/math/point_test.dart
index ef1fe5a..f15c635 100644
--- a/tests/html/point_test.dart
+++ b/tests/lib/math/point_test.dart
@@ -4,46 +4,43 @@
library point_test;
-import 'dart:html';
-import '../../pkg/unittest/lib/unittest.dart';
-import '../../pkg/unittest/lib/html_config.dart';
+import 'dart:math';
+import 'package:unittest/unittest.dart';
main() {
- useHtmlConfiguration();
-
test('constructor', () {
var point = new Point();
expect(point.x, 0);
expect(point.y, 0);
- expect('$point', '(0, 0)');
+ expect('$point', 'Point(0, 0)');
});
test('constructor X', () {
- var point = new Point(10);
+ var point = new Point<int>(10);
expect(point.x, 10);
expect(point.y, 0);
- expect('$point', '(10, 0)');
+ expect('$point', 'Point(10, 0)');
});
test('constructor X Y', () {
- var point = new Point(10, 20);
+ var point = new Point<int>(10, 20);
expect(point.x, 10);
expect(point.y, 20);
- expect('$point', '(10, 20)');
+ expect('$point', 'Point(10, 20)');
});
test('constructor X Y double', () {
- var point = new Point(10.5, 20.897);
+ var point = new Point<double>(10.5, 20.897);
expect(point.x, 10.5);
expect(point.y, 20.897);
- expect('$point', '(10.5, 20.897)');
+ expect('$point', 'Point(10.5, 20.897)');
});
test('constructor X Y NaN', () {
var point = new Point(double.NAN, 1000);
expect(point.x.isNaN, isTrue);
expect(point.y, 1000);
- expect('$point', '(NaN, 1000)');
+ expect('$point', 'Point(NaN, 1000)');
});
test('squaredDistanceTo', () {
@@ -72,38 +69,6 @@
expect(a + b, new Point(7, 60));
});
- test('ceil', () {
- var a = new Point(5.1, 10.8);
- expect(a.ceil(), new Point(6.0, 11.0));
-
- var b = new Point(5, 10);
- expect(b.ceil(), new Point(5, 10));
- });
-
- test('floor', () {
- var a = new Point(5.1, 10.8);
- expect(a.floor(), new Point(5.0, 10.0));
-
- var b = new Point(5, 10);
- expect(b.floor(), new Point(5, 10));
- });
-
- test('round', () {
- var a = new Point(5.1, 10.8);
- expect(a.round(), new Point(5.0, 11.0));
-
- var b = new Point(5, 10);
- expect(b.round(), new Point(5, 10));
- });
-
- test('toInt', () {
- var a = new Point(5.1, 10.8);
- var b = a.toInt();
- expect(b, new Point(5, 10));
- expect(b.x is int, isTrue);
- expect(b.y is int, isTrue);
- });
-
test('hashCode', () {
var a = new Point(0, 1);
var b = new Point(0, 1);
diff --git a/tests/lib/math/rectangle_test.dart b/tests/lib/math/rectangle_test.dart
new file mode 100644
index 0000000..2b214d2
--- /dev/null
+++ b/tests/lib/math/rectangle_test.dart
@@ -0,0 +1,131 @@
+// 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 rect_test;
+
+import 'dart:math';
+import 'package:unittest/unittest.dart';
+
+main() {
+ Rectangle createRectangle(List<num> a) {
+ return a != null ? new Rectangle(a[0], a[1], a[2] - a[0], a[3] - a[1])
+ : null;
+ }
+
+ test('construction', () {
+ var r0 = new Rectangle(10, 20, 30, 40);
+ expect(r0.toString(), 'Rectangle (10, 20) 30 x 40');
+ expect(r0.right, 40);
+ expect(r0.bottom, 60);
+
+ var r1 = new Rectangle.fromPoints(r0.topLeft, r0.bottomRight);
+ expect(r1, r0);
+
+ var r2 = new Rectangle.fromPoints(r0.bottomRight, r0.topLeft);
+ expect(r2, r0);
+ });
+
+ test('intersection', () {
+ var tests = [
+ [[10, 10, 20, 20], [15, 15, 25, 25], [15, 15, 20, 20]],
+ [[10, 10, 20, 20], [20, 0, 30, 10], [20, 10, 20, 10]],
+ [[0, 0, 1, 1], [10, 11, 12, 13], null],
+ [[11, 12, 98, 99], [22, 23, 34, 35], [22, 23, 34, 35]]];
+
+ for (var test in tests) {
+ var r0 = createRectangle(test[0]);
+ var r1 = createRectangle(test[1]);
+ var expected = createRectangle(test[2]);
+
+ expect(r0.intersection(r1), expected);
+ expect(r1.intersection(r0), expected);
+ }
+ });
+
+ test('intersects', () {
+ var r0 = new Rectangle(10, 10, 20, 20);
+ var r1 = new Rectangle(15, 15, 25, 25);
+ var r2 = new Rectangle(0, 0, 1, 1);
+
+ expect(r0.intersects(r1), isTrue);
+ expect(r1.intersects(r0), isTrue);
+
+ expect(r0.intersects(r2), isFalse);
+ expect(r2.intersects(r0), isFalse);
+ });
+
+ test('boundingBox', () {
+ var tests = [
+ [[10, 10, 20, 20], [15, 15, 25, 25], [10, 10, 25, 25]],
+ [[10, 10, 20, 20], [20, 0, 30, 10], [10, 0, 30, 20]],
+ [[0, 0, 1, 1], [10, 11, 12, 13], [0, 0, 12, 13]],
+ [[11, 12, 98, 99], [22, 23, 34, 35], [11, 12, 98, 99]]];
+
+ for (var test in tests) {
+ var r0 = createRectangle(test[0]);
+ var r1 = createRectangle(test[1]);
+ var expected = createRectangle(test[2]);
+
+ expect(r0.boundingBox(r1), expected);
+ expect(r1.boundingBox(r0), expected);
+ }
+ });
+
+ test('containsRectangle', () {
+ var r = new Rectangle(-10, 0, 20, 10);
+ expect(r.contains(r), isTrue);
+
+ expect(r.contains(
+ new Rectangle(double.NAN, double.NAN, double.NAN, double.NAN)), isFalse);
+
+ var r2 = new Rectangle(0, 2, 5, 5);
+ expect(r.contains(r2), isTrue);
+ expect(r2.contains(r), isFalse);
+
+ r2 = new Rectangle(-11, 2, 5, 5);
+ expect(r.contains(r2), isFalse);
+ r2 = new Rectangle(0, 2, 15, 5);
+ expect(r.contains(r2), isFalse);
+ r2 = new Rectangle(0, 2, 5, 10);
+ expect(r.contains(r2), isFalse);
+ r2 = new Rectangle(0, 0, 5, 10);
+ expect(r.contains(r2), isTrue);
+ });
+
+ test('containsPoint', () {
+ var r = new Rectangle(20, 40, 60, 80);
+
+ // Test middle.
+ expect(r.containsPoint(new Point(50, 80)), isTrue);
+
+ // Test edges.
+ expect(r.containsPoint(new Point(20, 40)), isTrue);
+ expect(r.containsPoint(new Point(50, 40)), isTrue);
+ expect(r.containsPoint(new Point(80, 40)), isTrue);
+ expect(r.containsPoint(new Point(80, 80)), isTrue);
+ expect(r.containsPoint(new Point(80, 120)), isTrue);
+ expect(r.containsPoint(new Point(50, 120)), isTrue);
+ expect(r.containsPoint(new Point(20, 120)), isTrue);
+ expect(r.containsPoint(new Point(20, 80)), isTrue);
+
+ // Test outside.
+ expect(r.containsPoint(new Point(0, 0)), isFalse);
+ expect(r.containsPoint(new Point(50, 0)), isFalse);
+ expect(r.containsPoint(new Point(100, 0)), isFalse);
+ expect(r.containsPoint(new Point(100, 80)), isFalse);
+ expect(r.containsPoint(new Point(100, 160)), isFalse);
+ expect(r.containsPoint(new Point(50, 160)), isFalse);
+ expect(r.containsPoint(new Point(0, 160)), isFalse);
+ expect(r.containsPoint(new Point(0, 80)), isFalse);
+ });
+
+ test('hashCode', () {
+ var a = new Rectangle(0, 1, 2, 3);
+ var b = new Rectangle(0, 1, 2, 3);
+ expect(a.hashCode, b.hashCode);
+
+ var c = new Rectangle(1, 0, 2, 3);
+ expect(a.hashCode == c.hashCode, isFalse);
+ });
+}
diff --git a/tests/lib/mirrors/constructor_kinds_test.dart b/tests/lib/mirrors/constructor_kinds_test.dart
new file mode 100644
index 0000000..f3339ca
--- /dev/null
+++ b/tests/lib/mirrors/constructor_kinds_test.dart
@@ -0,0 +1,104 @@
+// 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.constructor_kinds_test;
+
+import 'dart:mirrors';
+import 'package:expect/expect.dart';
+
+class ClassWithDefaultConstructor {}
+
+class Class {
+ Class.generative();
+ Class.redirectingGenerative() : this.generative();
+ factory Class.faktory () => new Class.generative();
+ factory Class.redirectingFactory() = Class.faktory;
+
+ const Class.constGenerative();
+ const Class.constRedirectingGenerative() : this.constGenerative();
+ // Not legal.
+ // const factory Class.constFaktory () => const Class.constGenerative();
+ const factory Class.constRedirectingFactory() = Class.constGenerative;
+}
+
+main() {
+ ClassMirror cm;
+ MethodMirror mm;
+
+ new Class.generative();
+ new Class.redirectingGenerative();
+ new Class.faktory();
+ new Class.redirectingFactory();
+ const Class.constGenerative();
+ const Class.constRedirectingGenerative();
+ const Class.constRedirectingFactory();
+
+ cm = reflectClass(ClassWithDefaultConstructor);
+ mm = cm.constructors.values.single;
+ Expect.isTrue(mm.isConstructor);
+ Expect.isTrue(mm.isGenerativeConstructor);
+ Expect.isFalse(mm.isFactoryConstructor);
+ Expect.isFalse(mm.isRedirectingConstructor);
+ Expect.isFalse(mm.isConstConstructor);
+
+
+ cm = reflectClass(Class);
+
+ mm = cm.constructors[#generative];
+ Expect.isTrue(mm.isConstructor);
+ Expect.isTrue(mm.isGenerativeConstructor);
+ Expect.isFalse(mm.isFactoryConstructor);
+ Expect.isFalse(mm.isRedirectingConstructor);
+ Expect.isFalse(mm.isConstConstructor);
+
+ mm = cm.constructors[#redirectingGenerative];
+ Expect.isTrue(mm.isConstructor);
+ Expect.isTrue(mm.isGenerativeConstructor);
+ Expect.isFalse(mm.isFactoryConstructor);
+ Expect.isTrue(mm.isRedirectingConstructor);
+ Expect.isFalse(mm.isConstConstructor);
+
+ mm = cm.constructors[#faktory];
+ Expect.isTrue(mm.isConstructor);
+ Expect.isFalse(mm.isGenerativeConstructor);
+ Expect.isTrue(mm.isFactoryConstructor);
+ Expect.isFalse(mm.isRedirectingConstructor);
+ Expect.isFalse(mm.isConstConstructor);
+
+ mm = cm.constructors[#redirectingFactory];
+ Expect.isTrue(mm.isConstructor);
+ Expect.isFalse(mm.isGenerativeConstructor);
+ Expect.isTrue(mm.isFactoryConstructor);
+ Expect.isTrue(mm.isRedirectingConstructor);
+ Expect.isFalse(mm.isConstConstructor);
+
+ mm = cm.constructors[#constGenerative];
+ Expect.isTrue(mm.isConstructor);
+ Expect.isTrue(mm.isGenerativeConstructor);
+ Expect.isFalse(mm.isFactoryConstructor);
+ Expect.isFalse(mm.isRedirectingConstructor);
+ Expect.isTrue(mm.isConstConstructor);
+
+ mm = cm.constructors[#constRedirectingGenerative];
+ Expect.isTrue(mm.isConstructor);
+ Expect.isTrue(mm.isGenerativeConstructor);
+ Expect.isFalse(mm.isFactoryConstructor);
+ Expect.isTrue(mm.isRedirectingConstructor);
+ Expect.isTrue(mm.isConstConstructor);
+
+ // Not legal.
+ // mm = cm.constructors[#constFaktory];
+ // Expect.isTrue(mm.isConstructor);
+ // Expect.isFalse(mm.isGenerativeConstructor);
+ // Expect.isTrue(mm.isFactoryConstructor);
+ // Expect.isFalse(mm.isRedirectingConstructor);
+ // Expect.isTrue(mm.isConstConstructor);
+
+ mm = cm.constructors[#constRedirectingFactory];
+ Expect.isTrue(mm.isConstructor);
+ Expect.isFalse(mm.isGenerativeConstructor);
+ Expect.isTrue(mm.isFactoryConstructor);
+ Expect.isTrue(mm.isRedirectingConstructor);
+ Expect.isTrue(mm.isConstConstructor);
+}
diff --git a/tests/lib/mirrors/constructors_test.dart b/tests/lib/mirrors/constructors_test.dart
index b42472f..b55e440a 100644
--- a/tests/lib/mirrors/constructors_test.dart
+++ b/tests/lib/mirrors/constructors_test.dart
@@ -27,7 +27,6 @@
}
main() {
- MirrorSystem mirrors = currentMirrorSystem();
ClassMirror fooMirror = reflectClass(Foo);
Map<Symbol, MethodMirror> fooConstructors = fooMirror.constructors;
ClassMirror barMirror = reflectClass(Bar);
diff --git a/tests/lib/mirrors/delegate_test.dart b/tests/lib/mirrors/delegate_test.dart
new file mode 100644
index 0000000..1f7edc6
--- /dev/null
+++ b/tests/lib/mirrors/delegate_test.dart
@@ -0,0 +1,52 @@
+// 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_named_test;
+
+import 'dart:mirrors';
+
+import 'package:expect/expect.dart';
+import 'invoke_test.dart';
+
+class C {
+ method(a, b, c) => "$a-$b-$c";
+ methodWithNamed(a, {b:'B', c}) => "$a-$b-$c";
+ methodWithOpt(a, [b, c='C']) => "$a-$b-$c";
+ get getter => 'g';
+ set setter(x) {
+ field = x*2;
+ return 'unobservable value';
+ }
+ var field;
+}
+
+class Proxy {
+ var targetMirror;
+ Proxy(target) : this.targetMirror = reflect(target);
+ noSuchMethod(invocation) => targetMirror.delegate(invocation);
+}
+
+main() {
+ var c = new C();
+ var proxy = new Proxy(c);
+ var result;
+
+ Expect.equals('X-Y-Z', proxy.method('X', 'Y', 'Z'));
+
+ Expect.equals('X-B-null', proxy.methodWithNamed('X'));
+ Expect.equals('X-Y-null', proxy.methodWithNamed('X', b: 'Y'));
+ Expect.equals('X-Y-Z', proxy.methodWithNamed('X', b: 'Y', c: 'Z'));
+
+ Expect.equals('X-null-C', proxy.methodWithOpt('X'));
+ Expect.equals('X-Y-C', proxy.methodWithOpt('X', 'Y'));
+ Expect.equals('X-Y-Z', proxy.methodWithOpt('X', 'Y', 'Z'));
+
+ Expect.equals('g', proxy.getter);
+
+ Expect.equals(5, proxy.setter = 5);
+ Expect.equals(10, proxy.field);
+
+ Expect.equals(5, proxy.field = 5);
+ Expect.equals(5, proxy.field);
+}
diff --git a/tests/lib/mirrors/generic_function_typedef_test.dart b/tests/lib/mirrors/generic_function_typedef_test.dart
new file mode 100644
index 0000000..051f25d
--- /dev/null
+++ b/tests/lib/mirrors/generic_function_typedef_test.dart
@@ -0,0 +1,113 @@
+// 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.generic_function_typedef;
+
+import 'dart:mirrors';
+
+import 'package:expect/expect.dart';
+
+import 'generics_test.dart';
+
+typedef bool NonGenericPredicate(num);
+typedef bool GenericPredicate<T>(T);
+typedef S GenericTransform<S>(S);
+
+class C<R> {
+ GenericPredicate<num> predicateOfNum;
+ GenericTransform<String> transformOfString;
+ GenericTransform<R> transformOfR;
+}
+
+main() {
+ TypeMirror dynamicMirror = currentMirrorSystem().dynamicType;
+
+ TypedefMirror predicateOfNum = reflectClass(C).variables[#predicateOfNum].type;
+ TypedefMirror transformOfString = reflectClass(C).variables[#transformOfString].type;
+ TypedefMirror transformOfR = reflectClass(C).variables[#transformOfR].type;
+ TypedefMirror transformOfDouble = reflect(new C<double>()).type.variables[#transformOfR].type;
+
+ TypeVariableMirror rFromC = reflectClass(C).typeVariables[0];
+
+ // Typedefs.
+ typeParameters(reflectClass(NonGenericPredicate), []);
+ typeParameters(reflectClass(GenericPredicate), [#T]);
+ typeParameters(reflectClass(GenericTransform), [#S]);
+ typeParameters(predicateOfNum, [#T]);
+ typeParameters(transformOfString, [#S]);
+ typeParameters(transformOfR, [#R]);
+ typeParameters(transformOfDouble, [#R]);
+
+ typeArguments(reflectClass(NonGenericPredicate), []);
+ typeArguments(reflectClass(GenericPredicate), []);
+ typeArguments(reflectClass(GenericTransform), []);
+ typeArguments(predicateOfNum, [reflectClass(num)]);
+ typeArguments(transformOfString, [reflectClass(String)]);
+ typeArguments(transformOfR, [rFromC]);
+ typeArguments(transformOfDouble, [reflect(double)]);
+
+ Expect.isTrue(reflectClass(NonGenericPredicate).isOriginalDeclaration);
+ Expect.isTrue(reflectClass(GenericPredicate).isOriginalDeclaration);
+ Expect.isTrue(reflectClass(GenericTransform).isOriginalDeclaration);
+ Expect.isFalse(predicateOfNum.isOriginalDeclaration);
+ Expect.isFalse(transformOfString.isOriginalDeclaration);
+ Expect.isFalse(transformOfR.isOriginalDeclaration);
+ Expect.isFalse(transformOfDouble.isOriginalDeclaration);
+
+ // Function types.
+ typeParameters(reflectClass(NonGenericPredicate).referent, []);
+ typeParameters(reflectClass(GenericPredicate).referent, []);
+ typeParameters(reflectClass(GenericTransform).referent, []);
+ typeParameters(predicateOfNum.referent, []);
+ typeParameters(transformOfString.referent, []);
+ typeParameters(transformOfR.referent, []);
+ typeParameters(transformOfDouble.referent, []);
+
+ typeArguments(reflectClass(NonGenericPredicate).referent, []);
+ typeArguments(reflectClass(GenericPredicate).referent, []);
+ typeArguments(reflectClass(GenericTransform).referent, []);
+ typeArguments(predicateOfNum.referent, []);
+ typeArguments(transformOfString.referent, []);
+ typeArguments(transformOfR.referent, []);
+ typeArguments(transformOfDouble.referent, []);
+
+ // Function types are always non-generic. Only the typedef is generic.
+ Expect.isTrue(reflectClass(NonGenericPredicate).referent.isOriginalDeclaration);
+ Expect.isTrue(reflectClass(GenericPredicate).referent.isOriginalDeclaration);
+ Expect.isTrue(reflectClass(GenericTransform).referent.isOriginalDeclaration);
+ Expect.isTrue(predicateOfNum.referent.isOriginalDeclaration);
+ Expect.isTrue(transformOfString.referent.isOriginalDeclaration);
+ Expect.isTrue(transformOfR.referent.isOriginalDeclaration); // Er, but here we don't have concrete types...
+ Expect.isTrue(transformOfDouble.referent.isOriginalDeclaration);
+
+ Expect.equals(reflectClass(num),
+ reflectClass(NonGenericPredicate).referent.parameters[0].type);
+ Expect.equals(dynamicMirror,
+ reflectClass(GenericPredicate).referent.parameters[0].type);
+ Expect.equals(dynamicMirror,
+ reflectClass(GenericTransform).referent.parameters[0].type);
+ Expect.equals(reflectClass(num),
+ predicateOfNum.referent.parameters[0].type);
+ Expect.equals(reflectClass(String),
+ transformOfString.referent.parameters[0].type);
+ Expect.equals(rFromC,
+ transformOfR.referent.parameters[0].type);
+ Expect.equals(reflectClass(double),
+ transformOfDouble.referent.parameters[0].type);
+
+ Expect.equals(reflectClass(bool),
+ reflectClass(NonGenericPredicate).referent.returnType);
+ Expect.equals(reflectClass(bool),
+ reflectClass(GenericPredicate).referent.returnType);
+ Expect.equals(dynamicMirror,
+ reflectClass(GenericTransform).referent.returnType);
+ Expect.equals(reflectClass(bool),
+ predicateOfNum.referent.returnType);
+ Expect.equals(reflectClass(String),
+ transformOfString.referent.returnType);
+ Expect.equals(rFromC,
+ transformOfR.referent.returnType);
+ Expect.equals(reflectClass(double),
+ transformOfDouble.referent.returnType);
+}
diff --git a/tests/lib/mirrors/generic_mixin_applications_test.dart b/tests/lib/mirrors/generic_mixin_applications_test.dart
new file mode 100644
index 0000000..47e6234
--- /dev/null
+++ b/tests/lib/mirrors/generic_mixin_applications_test.dart
@@ -0,0 +1,96 @@
+// 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.generic_mixin_applications;
+
+import 'dart:mirrors';
+
+import 'package:expect/expect.dart';
+
+import 'generics_test.dart';
+
+class Super<S> {}
+class Mixin<M> {}
+class Nixim<N> {}
+
+typedef NonGenericMixinApplication1 = Super with Mixin;
+typedef NonGenericMixinApplication2 = Super<num> with Mixin<String>;
+
+typedef GenericMixinApplication1<MA> = Super<MA> with Mixin<MA>;
+typedef GenericMixinApplication2<MA> = Super<num> with Mixin<String>;
+
+class NonGenericClass1 extends Super with Mixin {}
+class NonGenericClass2 extends Super<num> with Mixin<String> {}
+
+class GenericClass1<C> extends Super<C> with Mixin<C> {}
+class GenericClass2<C> extends Super<num> with Mixin<String> {}
+
+class GenericMultipleMixins<A, B, C> extends Super<A> with Mixin<B>, Nixim<C> {}
+
+main() {
+ TypeMirror dynamicMirror = currentMirrorSystem().dynamicType;
+
+ // Declarations.
+ typeParameters(reflectClass(NonGenericMixinApplication1), []);
+ typeParameters(reflectClass(NonGenericMixinApplication2), []);
+ typeParameters(reflectClass(GenericMixinApplication1), [#MA]);
+ typeParameters(reflectClass(GenericMixinApplication2), [#MA]);
+ typeParameters(reflectClass(NonGenericClass1), []);
+ typeParameters(reflectClass(NonGenericClass2), []);
+ typeParameters(reflectClass(GenericClass1), [#C]);
+ typeParameters(reflectClass(GenericClass2), [#C]);
+ typeParameters(reflectClass(GenericMultipleMixins), [#A, #B, #C]);
+ // Anonymous mixin applications have no type parameters or type arguments.
+ typeParameters(reflectClass(NonGenericClass1).superclass, []);
+ typeParameters(reflectClass(NonGenericClass2).superclass, []);
+ typeParameters(reflectClass(GenericClass1).superclass, []);
+ typeParameters(reflectClass(GenericClass2).superclass, []);
+
+ typeArguments(reflectClass(NonGenericMixinApplication1), []);
+ typeArguments(reflectClass(NonGenericMixinApplication2), []);
+ typeArguments(reflectClass(GenericMixinApplication1), []);
+ typeArguments(reflectClass(GenericMixinApplication2), []);
+ typeArguments(reflectClass(NonGenericClass1), []);
+ typeArguments(reflectClass(NonGenericClass2), []);
+ typeArguments(reflectClass(GenericClass1), []);
+ typeArguments(reflectClass(GenericClass2), []);
+ typeArguments(reflectClass(GenericMultipleMixins), []);
+ // Anonymous mixin applications have no type parameters or type arguments.
+ typeArguments(reflectClass(NonGenericClass1).superclass.originalDeclaration, []);
+ typeArguments(reflectClass(NonGenericClass2).superclass.originalDeclaration, []);
+ typeArguments(reflectClass(GenericClass1).superclass.originalDeclaration, []);
+ typeArguments(reflectClass(GenericClass2).superclass.originalDeclaration, []);
+
+
+ // Instantiations.
+ typeParameters(reflect(new NonGenericMixinApplication1()).type, []);
+ typeParameters(reflect(new NonGenericMixinApplication2()).type, []);
+ typeParameters(reflect(new GenericMixinApplication1<bool>()).type, [#MA]);
+ typeParameters(reflect(new GenericMixinApplication2<bool>()).type, [#MA]);
+ typeParameters(reflect(new NonGenericClass1()).type, []);
+ typeParameters(reflect(new NonGenericClass2()).type, []);
+ typeParameters(reflect(new GenericClass1<bool>()).type, [#C]);
+ typeParameters(reflect(new GenericClass2<bool>()).type, [#C]);
+ typeParameters(reflect(new GenericMultipleMixins<bool, String, int>()).type, [#A, #B, #C]);
+ // Anonymous mixin applications have no type parameters or type arguments.
+ typeParameters(reflect(new NonGenericClass1()).type.superclass, []);
+ typeParameters(reflect(new NonGenericClass2()).type.superclass, []);
+ typeParameters(reflect(new GenericClass1<bool>()).type.superclass, []);
+ typeParameters(reflect(new GenericClass2<bool>()).type.superclass, []);
+
+ typeArguments(reflect(new NonGenericMixinApplication1()).type, []);
+ typeArguments(reflect(new NonGenericMixinApplication2()).type, []);
+ typeArguments(reflect(new GenericMixinApplication1<bool>()).type, [reflectClass(bool)]);
+ typeArguments(reflect(new GenericMixinApplication2<bool>()).type, [reflectClass(bool)]);
+ typeArguments(reflect(new NonGenericClass1()).type, []);
+ typeArguments(reflect(new NonGenericClass2()).type, []);
+ typeArguments(reflect(new GenericClass1<bool>()).type, [reflectClass(bool)]);
+ typeArguments(reflect(new GenericClass2<bool>()).type, [reflectClass(bool)]);
+ typeArguments(reflect(new GenericMultipleMixins<bool, String, int>()).type, [reflectClass(bool), reflectClass(String), reflectClass(int)]);
+ // Anonymous mixin applications have no type parameters or type arguments.
+ typeArguments(reflect(new NonGenericClass1()).type.superclass, []);
+ typeArguments(reflect(new NonGenericClass2()).type.superclass, []);
+ typeArguments(reflect(new GenericClass1<bool>()).type.superclass, []);
+ typeArguments(reflect(new GenericClass2<bool>()).type.superclass, []);
+}
diff --git a/tests/lib/mirrors/generics_substitution_test.dart b/tests/lib/mirrors/generics_substitution_test.dart
new file mode 100644
index 0000000..2293e7d
--- /dev/null
+++ b/tests/lib/mirrors/generics_substitution_test.dart
@@ -0,0 +1,52 @@
+// 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.generics_substitution;
+
+import 'dart:mirrors';
+import 'package:expect/expect.dart';
+
+class SuperGeneric<R, S> {
+ R r;
+ s(S s) {}
+}
+
+class Generic<T> extends SuperGeneric<T, int> {
+ T t() {}
+}
+
+main() {
+ ClassMirror genericDecl = reflectClass(Generic);
+ ClassMirror genericOfString = reflect(new Generic<String>()).type;
+ ClassMirror superGenericDecl = reflectClass(SuperGeneric);
+ ClassMirror superOfTAndInt = genericDecl.superclass;
+ ClassMirror superOfStringAndInt = genericOfString.superclass;
+
+ Expect.isTrue(genericDecl.isOriginalDeclaration);
+ Expect.isFalse(genericOfString.isOriginalDeclaration);
+ Expect.isTrue(superGenericDecl.isOriginalDeclaration);
+ Expect.isFalse(superOfTAndInt.isOriginalDeclaration);
+ Expect.isFalse(superOfStringAndInt.isOriginalDeclaration);
+
+ Symbol r(ClassMirror cm) => cm.variables[#r].type.simpleName;
+ Symbol s(ClassMirror cm) => cm.methods[#s].parameters[0].type.simpleName;
+ Symbol t(ClassMirror cm) => cm.methods[#t].returnType.simpleName;
+
+ Expect.equals(#T, r(genericDecl.superclass));
+ Expect.equals(#int, s(genericDecl.superclass));
+ Expect.equals(#T, t(genericDecl));
+
+ Expect.equals(#String, r(genericOfString.superclass));
+ Expect.equals(#int, s(genericOfString.superclass));
+ Expect.equals(#String, t(genericOfString));
+
+ Expect.equals(#R, r(superGenericDecl));
+ Expect.equals(#S, s(superGenericDecl));
+
+ Expect.equals(#T, r(superOfTAndInt));
+ Expect.equals(#int, s(superOfTAndInt));
+
+ Expect.equals(#String, r(superOfStringAndInt));
+ Expect.equals(#int, t(superOfStringAndInt));
+}
diff --git a/tests/lib/mirrors/generics_test.dart b/tests/lib/mirrors/generics_test.dart
index 7f6386a..8eb63ee 100644
--- a/tests/lib/mirrors/generics_test.dart
+++ b/tests/lib/mirrors/generics_test.dart
@@ -22,7 +22,7 @@
class I extends G {}
typeParameters(mirror, parameterNames) {
- Expect.listEquals(parameterNames.map((n) => new Symbol(n)).toList(),
+ Expect.listEquals(parameterNames,
mirror.typeVariables.map((v) => v.simpleName).toList());
}
@@ -32,15 +32,15 @@
main() {
// Declarations.
- typeParameters(reflectClass(A), ['T']);
+ typeParameters(reflectClass(A), [#T]);
typeParameters(reflectClass(G), []);
typeParameters(reflectClass(B), []);
typeParameters(reflectClass(C), []);
typeParameters(reflectClass(D), []);
- typeParameters(reflectClass(E), ['S']);
- typeParameters(reflectClass(F), ['R']);
+ typeParameters(reflectClass(E), [#S]);
+ typeParameters(reflectClass(F), [#R]);
typeParameters(reflectClass(G), []);
- typeParameters(reflectClass(H), ['A', 'B', 'C']);
+ typeParameters(reflectClass(H), [#A, #B, #C]);
typeParameters(reflectClass(I), []);
typeArguments(reflectClass(A), []);
@@ -74,14 +74,14 @@
Expect.equals(reflectClass(I), reflectClass(I).originalDeclaration);
// Instantiations.
- typeParameters(reflect(new A<num>()).type, ['T']);
+ typeParameters(reflect(new A<num>()).type, [#T]);
typeParameters(reflect(new B<num>()).type, []);
typeParameters(reflect(new C()).type, []);
typeParameters(reflect(new D()).type, []);
- typeParameters(reflect(new E()).type, ['S']);
- typeParameters(reflect(new F<num>()).type, ['R']);
+ typeParameters(reflect(new E()).type, [#S]);
+ typeParameters(reflect(new F<num>()).type, [#R]);
typeParameters(reflect(new G()).type, []);
- typeParameters(reflect(new H()).type, ['A', 'B', 'C']);
+ typeParameters(reflect(new H()).type, [#A, #B, #C]);
typeParameters(reflect(new I()).type, []);
var numMirror = reflectClass(num);
@@ -154,7 +154,7 @@
// Library members are all uninstantaited generics or non-generics.
currentMirrorSystem().libraries.values.forEach((libraryMirror) {
libraryMirror.classes.values.forEach((classMirror) {
- // TODO(12282): Deal with generic typedefs.
+ // Generic typedefs are considered in a separate test.
if (classMirror is! TypedefMirror) {
Expect.isTrue(classMirror.isOriginalDeclaration);
Expect.equals(classMirror, classMirror.originalDeclaration);
diff --git a/tests/lib/mirrors/initializing_formals_test.dart b/tests/lib/mirrors/initializing_formals_test.dart
new file mode 100644
index 0000000..6dcfce1
--- /dev/null
+++ b/tests/lib/mirrors/initializing_formals_test.dart
@@ -0,0 +1,110 @@
+// 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.initializing_formals;
+
+import 'dart:mirrors';
+import 'package:expect/expect.dart';
+
+class Class<T> {
+ int intField;
+ bool boolField;
+ String stringField;
+ T tField;
+ dynamic _privateField;
+
+ Class.nongeneric(this.intField);
+ Class.named({this.boolField});
+ Class.optPos([this.stringField = 'default']);
+ Class.generic(this.tField);
+ Class.private(this._privateField);
+}
+
+class Constant {
+ final value;
+ const Constant(this.value);
+ const Constant.marked(final this.value);
+}
+
+main() {
+ ParameterMirror pm;
+
+ pm = reflectClass(Class).constructors[#Class.nongeneric].parameters.single;
+ Expect.equals(#intField, pm.simpleName);
+ Expect.equals(reflectClass(int), pm.type); /// 01: ok
+ Expect.isFalse(pm.isNamed);
+ Expect.isFalse(pm.isFinal);
+ Expect.isFalse(pm.isOptional);
+ Expect.isFalse(pm.hasDefaultValue);
+ Expect.isFalse(pm.isPrivate);
+ Expect.isFalse(pm.isStatic);
+ Expect.isFalse(pm.isTopLevel);
+
+ pm = reflectClass(Class).constructors[#Class.named].parameters.single;
+ Expect.equals(#boolField, pm.simpleName);
+ Expect.equals(reflectClass(bool), pm.type); /// 01: ok
+ Expect.isTrue(pm.isNamed);
+ Expect.isFalse(pm.isFinal);
+ Expect.isTrue(pm.isOptional);
+ Expect.isFalse(pm.hasDefaultValue);
+ Expect.isFalse(pm.isPrivate);
+ Expect.isFalse(pm.isStatic);
+ Expect.isFalse(pm.isTopLevel);
+
+ pm = reflectClass(Class).constructors[#Class.optPos].parameters.single;
+ Expect.equals(#stringField, pm.simpleName);
+ Expect.equals(reflectClass(String), pm.type); /// 01: ok
+ Expect.isFalse(pm.isNamed);
+ Expect.isFalse(pm.isFinal);
+ Expect.isTrue(pm.isOptional);
+ Expect.isTrue(pm.hasDefaultValue);
+ Expect.equals('default', pm.defaultValue.reflectee);
+ Expect.isFalse(pm.isPrivate);
+ Expect.isFalse(pm.isStatic);
+ Expect.isFalse(pm.isTopLevel);
+
+ pm = reflectClass(Class).constructors[#Class.generic].parameters.single;
+ Expect.equals(#tField, pm.simpleName);
+ Expect.equals(reflectClass(Class).typeVariables.single, pm.type); /// 01: ok
+ Expect.isFalse(pm.isNamed);
+ Expect.isFalse(pm.isFinal);
+ Expect.isFalse(pm.isOptional);
+ Expect.isFalse(pm.hasDefaultValue);
+ Expect.isFalse(pm.isPrivate);
+ Expect.isFalse(pm.isStatic);
+ Expect.isFalse(pm.isTopLevel);
+
+ pm = reflectClass(Class).constructors[#Class.private].parameters.single;
+ Expect.equals(#_privateField, pm.simpleName);
+ Expect.equals(currentMirrorSystem().dynamicType, pm.type);
+ Expect.isFalse(pm.isNamed);
+ Expect.isFalse(pm.isFinal);
+ Expect.isFalse(pm.isOptional);
+ Expect.isFalse(pm.hasDefaultValue);
+ Expect.isTrue(pm.isPrivate);
+ Expect.isFalse(pm.isStatic);
+ Expect.isFalse(pm.isTopLevel);
+
+ pm = reflectClass(Constant).constructors[#Constant].parameters.single;
+ Expect.equals(#value, pm.simpleName);
+ Expect.equals(currentMirrorSystem().dynamicType, pm.type);
+ Expect.isFalse(pm.isNamed);
+ Expect.isFalse(pm.isFinal); // N.B.
+ Expect.isFalse(pm.isOptional);
+ Expect.isFalse(pm.hasDefaultValue);
+ Expect.isFalse(pm.isPrivate);
+ Expect.isFalse(pm.isStatic);
+ Expect.isFalse(pm.isTopLevel);
+
+ pm = reflectClass(Constant).constructors[#Constant.marked].parameters.single;
+ Expect.equals(#value, pm.simpleName);
+ Expect.equals(currentMirrorSystem().dynamicType, pm.type);
+ Expect.isFalse(pm.isNamed);
+ Expect.isTrue(pm.isFinal); // N.B.
+ Expect.isFalse(pm.isOptional);
+ Expect.isFalse(pm.hasDefaultValue);
+ Expect.isFalse(pm.isPrivate);
+ Expect.isFalse(pm.isStatic);
+ Expect.isFalse(pm.isTopLevel);
+}
diff --git a/tests/lib/mirrors/reflect_class_test.dart b/tests/lib/mirrors/reflect_class_test.dart
new file mode 100644
index 0000000..c556ba8
--- /dev/null
+++ b/tests/lib/mirrors/reflect_class_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.
+
+import "dart:mirrors";
+
+import "package:expect/expect.dart";
+
+typedef void FooFunction(int a, double b);
+
+main() {
+ Function expectedError = (e) => e is ArgumentError || e is TypeError;
+
+ Expect.throws(() => reflectClass(dynamic), expectedError);
+ Expect.throws(() => reflectClass(1), expectedError);
+ Expect.throws(() => reflectClass("string"), expectedError);
+
+ // reflectClass() on a function type should fail once typedefs are represented
+ // by TypedefMirrors instead of ClassMirrors.
+ // Expect.throws(() => reflectClass(FooFunction), expectedError);
+}
diff --git a/tests/lib/mirrors/type_argument_is_type_variable_test.dart b/tests/lib/mirrors/type_argument_is_type_variable_test.dart
new file mode 100644
index 0000000..90ae8fe
--- /dev/null
+++ b/tests/lib/mirrors/type_argument_is_type_variable_test.dart
@@ -0,0 +1,52 @@
+// 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.type_argument_is_type_variable;
+
+import 'dart:mirrors';
+
+import 'package:expect/expect.dart';
+
+import 'generics_test.dart';
+
+class SuperSuper<SS> {}
+class Super<S> extends SuperSuper<S> {}
+class Generic<G> extends Super<G> {}
+
+main() {
+ // Declarations.
+ ClassMirror generic = reflectClass(Generic);
+ ClassMirror superOfGeneric = generic.superclass;
+ ClassMirror superOfSuperOfGeneric = superOfGeneric.superclass;
+