Version 0.5.10.0
svn merge -r 22870:23017 https://dart.googlecode.com/svn/branches/bleeding_edge trunk
git-svn-id: http://dart.googlecode.com/svn/trunk@23028 260f80e4-7a28-3924-810f-c04153c831b5
diff --git a/pkg/args/lib/args.dart b/pkg/args/lib/args.dart
index be1a6ef..3898b9f 100644
--- a/pkg/args/lib/args.dart
+++ b/pkg/args/lib/args.dart
@@ -169,17 +169,46 @@
* option passed to the command. You can add a command like so:
*
* var parser = new ArgParser();
- * var command = parser.addCommand("commit");
+ * var command = parser.addCommand('commit');
+ *
+ * It returns another [ArgParser] which you can then use to define options
+ * specific to that command. If you already have an [ArgParser] for the
+ * command's options, you can pass it to [addCommand]:
+ *
+ * var parser = new ArgParser();
+ * var command = new ArgParser();
+ * parser.addCommand('commit', command);
+ *
+ * The [ArgParser] for a command can then define whatever options or flags:
+ *
* command.addFlag('all', abbr: 'a');
*
- * It returns another [ArgParser] which you can use to define options and
- * subcommands on that command. When an argument list is parsed, you can then
- * determine which command was entered and what options were provided for it.
+ * You can add multiple commands to the same parser so that a user can select
+ * one from a range of possible commands. When an argument list is parsed,
+ * you can then determine which command was entered and what options were
+ * provided for it.
*
* var results = parser.parse(['commit', '-a']);
* print(results.command.name); // "commit"
* print(results.command['a']); // true
*
+ * Options for a command must appear after the command in the argument list.
+ * For example, given the above parser, "git -a commit" is *not* valid. The
+ * parser will try to find the right-most command that accepts an option. For
+ * example:
+ *
+ * var parser = new ArgParser();
+ * parser.addFlag('all', abbr: 'a');
+ * var command = new ArgParser().addCommand('commit');
+ * parser.addFlag('all', abbr: 'a');
+ * var results = parser.parse(['commit', '-a']);
+ * print(results.command['a']); // true
+ *
+ * Here, both the top-level parser and the "commit" command can accept a "-a"
+ * (which is probably a bad command line interface, admittedly). In that case,
+ * when "-a" appears after "commit", it will be applied to that command. If it
+ * appears to the left of "commit", it will be given to the top-level parser.
+ *
* ## Displaying usage ##
*
* This library can also be used to automatically generate nice usage help
@@ -248,19 +277,21 @@
ArgParser();
/**
- * Defines a command. A command is a named argument which may in turn
- * define its own options and subcommands. Returns an [ArgParser] that can
- * be used to define the command's options.
+ * Defines a command.
+ *
+ * A command is a named argument which may in turn define its own options and
+ * subcommands using the given parser. If [parser] is omitted, implicitly
+ * creates a new one. Returns the parser for the command.
*/
- ArgParser addCommand(String name) {
+ ArgParser addCommand(String name, [ArgParser parser]) {
// Make sure the name isn't in use.
if (commands.containsKey(name)) {
throw new ArgumentError('Duplicate command "$name".');
}
- var command = new ArgParser();
- commands[name] = command;
- return command;
+ if (parser == null) parser = new ArgParser();
+ commands[name] = parser;
+ return parser;
}
/**
diff --git a/pkg/args/test/command_test.dart b/pkg/args/test/command_test.dart
index 5079425..6115ab1 100644
--- a/pkg/args/test/command_test.dart
+++ b/pkg/args/test/command_test.dart
@@ -9,6 +9,21 @@
main() {
group('ArgParser.addCommand()', () {
+ test('creates a new ArgParser if none is given', () {
+ var parser = new ArgParser();
+ var command = parser.addCommand('install');
+ expect(parser.commands['install'], equals(command));
+ expect(command is ArgParser, isTrue);
+ });
+
+ test('uses the command parser if given one', () {
+ var parser = new ArgParser();
+ var command = new ArgParser();
+ var result = parser.addCommand('install', command);
+ expect(parser.commands['install'], equals(command));
+ expect(result, equals(command));
+ });
+
test('throws on a duplicate command name', () {
var parser = new ArgParser();
parser.addCommand('install');
diff --git a/pkg/pkg.status b/pkg/pkg.status
index 6f9e10e..e4229f4 100644
--- a/pkg/pkg.status
+++ b/pkg/pkg.status
@@ -126,6 +126,17 @@
unittest/test/mock_test: Fail
unittest/test/mock_regexp_negative_test: Fail
+# The unminified unittest tests test that the real names of Dart types are
+# printed. Minified versions of these tests exist that test the behavior when
+# minified.
+unittest/test/*_unminified_test: Skip
+
+[ $minified == false ]
+# The minified unittest tests test that the minified names of Dart types are
+# printed. Unminified versions of these tests exist that test the behavior when
+# not minified.
+unittest/test/*_minified_test: Skip
+
[ $compiler == none && $runtime == drt ]
dartdoc/test/dartdoc_test: Skip # See dartbug.com/4541.
diff --git a/pkg/scheduled_test/test/descriptor/file_test.dart b/pkg/scheduled_test/test/descriptor/file_test.dart
index 5b64577..958f431 100644
--- a/pkg/scheduled_test/test/descriptor/file_test.dart
+++ b/pkg/scheduled_test/test/descriptor/file_test.dart
@@ -229,7 +229,7 @@
test('test 2', () {
expect(errors, everyElement(new isInstanceOf<ScheduleError>()));
expect(errors.map((e) => e.error.message), equals([
- "Expected: contains 'baaz'\n but: was 'barfoobaz'.\n"
+ "Expected: contains 'baaz'\n But: was 'barfoobaz'.\n"
]), verbose: true);
});
}, passing: ['test 2']);
@@ -270,7 +270,7 @@
expect(errors, everyElement(new isInstanceOf<ScheduleError>()));
expect(errors.map((e) => e.error.message), equals([
"Expected: contains <12>\n"
- " but: was <[98, 97, 114, 102, 111, 111, 98, 97, 122]>.\n"
+ " But: was [98, 97, 114, 102, 111, 111, 98, 97, 122].\n"
]), verbose: true);
});
}, passing: ['test 2']);
diff --git a/pkg/unittest/lib/matcher.dart b/pkg/unittest/lib/matcher.dart
index fd6412e..1bdb226 100644
--- a/pkg/unittest/lib/matcher.dart
+++ b/pkg/unittest/lib/matcher.dart
@@ -29,6 +29,9 @@
import 'dart:async';
+import 'src/pretty_print.dart';
+import 'src/utils.dart';
+
part 'src/basematcher.dart';
part 'src/iterable_matchers.dart';
part 'src/core_matchers.dart';
diff --git a/pkg/unittest/lib/src/core_matchers.dart b/pkg/unittest/lib/src/core_matchers.dart
index 980e7a0..1c8d2f6 100644
--- a/pkg/unittest/lib/src/core_matchers.dart
+++ b/pkg/unittest/lib/src/core_matchers.dart
@@ -173,26 +173,14 @@
}
} else {
reason = new StringDescription();
- var eType = typeName(expected);
- var aType = typeName(actual);
- var includeTypes = eType != aType;
// If we have recursed, show the expected value too; if not,
// expect() will show it for us.
if (depth > 0) {
reason.add('expected ');
- if (includeTypes) {
- reason.add(eType).add(':');
- }
reason.addDescriptionOf(expected).add(' but ');
}
reason.add('was ');
- if (includeTypes) {
- reason.add(aType).add(':');
- }
reason.addDescriptionOf(actual);
- if (includeTypes && depth == 0) {
- reason.add(' (not type ').add(eType).add(')');
- }
}
}
if (reason != null && location.length > 0) {
@@ -201,17 +189,6 @@
return reason;
}
- String typeName(x) {
- // dart2js blows up on some objects (e.g. window.navigator).
- // So we play safe here.
- try {
- if (x == null) return "null";
- return x.runtimeType.toString();
- } catch (e) {
- return "Unknown";
- }
- }
-
String _match(expected, actual) {
Description reason = _recursiveMatch(expected, actual, '', 0);
return reason == null ? null : reason.toString();
@@ -583,17 +560,16 @@
Description describeMismatch(item, Description mismatchDescription,
MatchState matchState, bool verbose) {
- super.describeMismatch(item, mismatchDescription, matchState, verbose);
try {
// We want to generate a different description if there is no length
// property. This is harmless code that will throw if no length property
// but subtle enough that an optimizer shouldn't strip it out.
if (item.length * item.length >= 0) {
- return mismatchDescription.add(' with length of ').
+ return mismatchDescription.add('had length of ').
addDescriptionOf(item.length);
}
} catch (e) {
- return mismatchDescription.add(' has no length property');
+ return mismatchDescription.add('had no length property');
}
}
}
diff --git a/pkg/unittest/lib/src/description.dart b/pkg/unittest/lib/src/description.dart
index cdd8193..cde5243 100644
--- a/pkg/unittest/lib/src/description.dart
+++ b/pkg/unittest/lib/src/description.dart
@@ -41,23 +41,8 @@
Description addDescriptionOf(value) {
if (value is Matcher) {
value.describe(this);
- } else if (value is String) {
- _addEscapedString(value);
} else {
- String description = (value == null) ? "null" : value.toString();
- if (description.startsWith('<') && description.endsWith('>')) {
- add(description);
- } else if (description.startsWith("Instance of")) {
- add('<');
- add(description);
- add(':');
- add(value.hashCode.toString());
- add('>');
- } else {
- add('<');
- add(description);
- add('>');
- }
+ add(prettyPrint(value, maxLineLength: 80, maxItems: 25));
}
return this;
}
@@ -85,23 +70,7 @@
/** Escape the control characters in [string] so that they are visible. */
_addEscapedString(String string) {
add("'");
- for (var i = 0; i < string.length; i++) {
- add(_escape(string[i]));
- }
+ add(escapeString(string));
add("'");
}
-
- /** Return the escaped form of a character [ch]. */
- _escape(ch) {
- if (ch == "'")
- return "\'";
- else if (ch == '\n')
- return '\\n';
- else if (ch == '\r')
- return '\\r';
- else if (ch == '\t')
- return '\\t';
- else
- return ch;
- }
}
diff --git a/pkg/unittest/lib/src/expect.dart b/pkg/unittest/lib/src/expect.dart
index 3542f7a..f10309d 100644
--- a/pkg/unittest/lib/src/expect.dart
+++ b/pkg/unittest/lib/src/expect.dart
@@ -137,28 +137,15 @@
String _defaultErrorFormatter(actual, Matcher matcher, String reason,
MatchState matchState, bool verbose) {
var description = new StringDescription();
- description.add('Expected: ').addDescriptionOf(matcher).
- add('\n but: ');
- matcher.describeMismatch(actual, description, matchState, verbose);
- description.add('.\n');
- if (verbose) {
- if (actual is Iterable) {
- description.add('Actual: ').addDescriptionOf(actual).add('\n');
- } else if (actual is Map) {
- description.add('Actual: ');
- var count = 25;
- for (var k in actual.keys) {
- if (count == 0) {
- description.add('...\n');
- break;
- }
- description.addDescriptionOf(k);
- description.add(' : ');
- description.addDescriptionOf(actual[k]);
- description.add('\n');
- --count;
- }
- }
+ description.add('Expected: ').addDescriptionOf(matcher).add('\n');
+
+ var mismatchDescription = new StringDescription();
+ matcher.describeMismatch(actual, mismatchDescription, matchState, verbose);
+ description.add(' But: ')
+ .add(mismatchDescription.toString()).add('.\n');
+
+ if (!mismatchDescription.toString().startsWith("was ")) {
+ description.add('Actual: ').addDescriptionOf(actual);
}
if (reason != null) {
description.add(reason).add('\n');
diff --git a/pkg/unittest/lib/src/iterable_matchers.dart b/pkg/unittest/lib/src/iterable_matchers.dart
index acf41d0..65bc610 100644
--- a/pkg/unittest/lib/src/iterable_matchers.dart
+++ b/pkg/unittest/lib/src/iterable_matchers.dart
@@ -42,8 +42,9 @@
if (matchState.state != null) {
var index = matchState.state['index'];
var element = matchState.state['element'];
+ mismatchDescription.add('position $index ');
return _matcher.describeMismatch(element, mismatchDescription,
- matchState.state['state'], verbose).add(' at position $index');
+ matchState.state['state'], verbose);
}
return super.describeMismatch(item, mismatchDescription,
matchState, verbose);
diff --git a/pkg/unittest/lib/src/map_matchers.dart b/pkg/unittest/lib/src/map_matchers.dart
index eccc4ec..72984f9 100644
--- a/pkg/unittest/lib/src/map_matchers.dart
+++ b/pkg/unittest/lib/src/map_matchers.dart
@@ -44,8 +44,8 @@
Description describeMismatch(item, Description mismatchDescription,
MatchState matchState, bool verbose) {
if (!item.containsKey(_key)) {
- return mismatchDescription.addDescriptionOf(item).
- add(" doesn't contain key ").addDescriptionOf(_key);
+ return mismatchDescription.add(" doesn't contain key ")
+ .addDescriptionOf(_key);
} else {
mismatchDescription.add(' contains key ').addDescriptionOf(_key).
add(' but with value ');
diff --git a/pkg/unittest/lib/src/numeric_matchers.dart b/pkg/unittest/lib/src/numeric_matchers.dart
index e5dd7ef..84afb49 100644
--- a/pkg/unittest/lib/src/numeric_matchers.dart
+++ b/pkg/unittest/lib/src/numeric_matchers.dart
@@ -150,14 +150,11 @@
Description describeMismatch(item, Description mismatchDescription,
MatchState matchState, bool verbose) {
if (item is !num) {
- return mismatchDescription.
- addDescriptionOf(item).
- add(' not numeric');
+ return mismatchDescription.add(' not numeric');
} else {
var diff = item - _value;
if (diff < 0) diff = -diff;
return mismatchDescription.
- addDescriptionOf(item).
add(' differed by ').
addDescriptionOf(diff);
}
diff --git a/pkg/unittest/lib/src/operator_matchers.dart b/pkg/unittest/lib/src/operator_matchers.dart
index d5142be..c7421b7 100644
--- a/pkg/unittest/lib/src/operator_matchers.dart
+++ b/pkg/unittest/lib/src/operator_matchers.dart
@@ -94,9 +94,9 @@
Description describeMismatch(item, Description mismatchDescription,
MatchState matchState, bool verbose) {
var matcher = matchState.state['matcher'];
- mismatchDescription.addDescriptionOf(matcher).add(' ');
- matcher.describeMismatch(item, mismatchDescription,
- matchState.state['state'], verbose);
+ matcher.describeMismatch(item, mismatchDescription,
+ matchState.state['state'], verbose);
+ mismatchDescription.add(" (wasn't ").addDescriptionOf(matcher).add(')');
return mismatchDescription;
}
diff --git a/pkg/unittest/lib/src/pretty_print.dart b/pkg/unittest/lib/src/pretty_print.dart
new file mode 100644
index 0000000..1608e10
--- /dev/null
+++ b/pkg/unittest/lib/src/pretty_print.dart
@@ -0,0 +1,102 @@
+// 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 pretty_print;
+
+import 'utils.dart';
+
+/**
+ * Returns a pretty-printed representation of [object].
+ *
+ * If [maxLineLength] is passed, this will attempt to ensure that each line is
+ * no longer than [maxLineLength] characters long. This isn't guaranteed, since
+ * individual objects may have string representations that are too long, but
+ * most lines will be less than [maxLineLength] long.
+ *
+ * If [maxItems] is passed, [Iterable]s and [Map]s will only print their first
+ * [maxItems] members or key/value pairs, respectively.
+ */
+String prettyPrint(object, {int maxLineLength, int maxItems}) {
+ String _prettyPrint(object, int indent, Set seen, bool top) {
+ // Avoid looping infinitely on recursively-nested data structures.
+ if (seen.contains(object)) return "(recursive)";
+ seen = seen.union(new Set.from([object]));
+ String pp(child) => _prettyPrint(child, indent + 2, seen, false);
+
+ if (object is Iterable) {
+ // Print the type name for non-List iterables.
+ var type = object is List ? "" : typeName(object) + ":";
+
+ // Truncate the list of strings if it's longer than [maxItems].
+ var strings = object.map(pp).toList();
+ if (maxItems != null && strings.length > maxItems) {
+ strings.replaceRange(maxItems - 1, strings.length, ['...']);
+ }
+
+ // If the printed string is short and doesn't contain a newline, print it
+ // as a single line.
+ var singleLine = "$type[${strings.join(', ')}]";
+ if ((maxLineLength == null ||
+ singleLine.length + indent <= maxLineLength) &&
+ !singleLine.contains("\n")) {
+ return singleLine;
+ }
+
+ // Otherwise, print each member on its own line.
+ return "$type[\n" + strings.map((string) {
+ return _indent(indent + 2) + string;
+ }).join(",\n") + "\n" + _indent(indent) + "]";
+ } else if (object is Map) {
+ // Convert the contents of the map to string representations.
+ var strings = object.keys.map((key) {
+ return '${pp(key)}: ${pp(object[key])}';
+ }).toList();
+
+ // Truncate the list of strings if it's longer than [maxItems].
+ if (maxItems != null && strings.length > maxItems) {
+ strings.replaceRange(maxItems - 1, strings.length, ['...']);
+ }
+
+ // If the printed string is short and doesn't contain a newline, print it
+ // as a single line.
+ var singleLine = "{${strings.join(", ")}}";
+ if ((maxLineLength == null ||
+ singleLine.length + indent <= maxLineLength) &&
+ !singleLine.contains("\n")) {
+ return singleLine;
+ }
+
+ // Otherwise, print each key/value pair on its own line.
+ return "{\n" + strings.map((string) {
+ return _indent(indent + 2) + string;
+ }).join(",\n") + "\n" + _indent(indent) + "}";
+ } else if (object is String) {
+ // Escape strings and print each line on its own line.
+ var lines = object.split("\n");
+ return "'" + lines.map(escapeString)
+ .join("\\n'\n${_indent(indent + 2)}'") + "'";
+ } else {
+ var value = object.toString().replaceAll("\n", _indent(indent) + "\n");
+ var defaultToString = value.startsWith("Instance of ");
+
+ // If this is the top-level call to [prettyPrint], wrap the value on angle
+ // brackets to set it apart visually.
+ if (top) value = "<$value>";
+
+ // Print the type of objects with custom [toString] methods. Primitive
+ // objects and objects that don't implement a custom [toString] don't need
+ // to have their types printed.
+ if (object is num || object is bool || object is Function ||
+ object == null || defaultToString) {
+ return value;
+ } else {
+ return "${typeName(object)}:$value";
+ }
+ }
+ }
+
+ return _prettyPrint(object, 0, new Set(), true);
+}
+
+String _indent(int length) => new List.filled(length, ' ').join('');
diff --git a/pkg/unittest/lib/src/utils.dart b/pkg/unittest/lib/src/utils.dart
new file mode 100644
index 0000000..6442ac4
--- /dev/null
+++ b/pkg/unittest/lib/src/utils.dart
@@ -0,0 +1,48 @@
+// 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 utils;
+
+/**
+ * Returns the name of the type of [x], or "Unknown" if the type name can't be
+ * determined.
+ */
+String typeName(x) {
+ // dart2js blows up on some objects (e.g. window.navigator).
+ // So we play safe here.
+ try {
+ if (x == null) return "null";
+ var type = x.runtimeType.toString();
+ // TODO(nweiz): if the object's type is private, find a public superclass to
+ // display once there's a portable API to do that.
+ return type.startsWith("_") ? "?" : type;
+ } catch (e) {
+ return "?";
+ }
+}
+
+/**
+ * Returns [source] with any control characters replaced by their escape
+ * sequences.
+ *
+ * This doesn't add quotes to the string, but it does escape single quote
+ * characters so that single quotes can be applied externally.
+ */
+String escapeString(String source) =>
+ source.split("").map(_escapeChar).join("");
+
+/** Return the escaped form of a character [ch]. */
+String _escapeChar(String ch) {
+ if (ch == "'")
+ return "\\'";
+ else if (ch == '\n')
+ return '\\n';
+ else if (ch == '\r')
+ return '\\r';
+ else if (ch == '\t')
+ return '\\t';
+ else
+ return ch;
+}
+
diff --git a/pkg/unittest/test/instance_test.dart b/pkg/unittest/test/instance_test.dart
index deb1c21..bda0561 100644
--- a/pkg/unittest/test/instance_test.dart
+++ b/pkg/unittest/test/instance_test.dart
@@ -5,9 +5,7 @@
library unittestTests;
import 'package:unittest/unittest.dart';
-part 'test_utils.dart';
-
-doesThrow() { throw 'X'; }
+import 'test_utils.dart';
main() {
initUtils();
@@ -15,15 +13,17 @@
group('Type Matchers', () {
test('isInstanceOf', () {
shouldFail(0, new isInstanceOf<String>('String'),
- "Expected: an instance of String but: was <0>.");
+ "Expected: an instance of String But: was <0>.");
shouldPass('cow', new isInstanceOf<String>('String'));
});
test('throwsA', () {
shouldPass(doesThrow, throwsA(equals('X')));
shouldFail(doesThrow, throwsA(equals('Y')),
- "Expected: throws an exception which matches 'Y' "
- "but: exception 'X' does not match 'Y'.");
+ "Expected: throws an exception which matches 'Y' "
+ "But: exception 'X' does not match 'Y'. "
+ "Actual: <Closure: (dynamic) => dynamic "
+ "from Function 'doesThrow': static.>");
});
});
}
diff --git a/pkg/unittest/test/matchers_minified_test.dart b/pkg/unittest/test/matchers_minified_test.dart
new file mode 100644
index 0000000..3fb875d
--- /dev/null
+++ b/pkg/unittest/test/matchers_minified_test.dart
@@ -0,0 +1,140 @@
+// 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.
+
+// This file is for matcher tests that rely on the names of various Dart types.
+// These tests normally fail when run in minified dart2js, since the names will
+// be mangled. This version of the file is modified to expect minified names.
+
+import 'package:unittest/unittest.dart';
+
+import 'test_common.dart';
+import 'test_utils.dart';
+
+// A regexp fragment matching a minified name.
+final _minifiedName = r"[A-Za-z0-9]{1,3}";
+
+void main() {
+ initUtils();
+
+ group('Core matchers', () {
+ test('throwsFormatException', () {
+ shouldPass(() { throw new FormatException(''); },
+ throwsFormatException);
+ shouldFail(() { throw new Exception(); },
+ throwsFormatException,
+ matches(
+ r"Expected: throws an exception which matches FormatException +"
+ r"But: exception " + _minifiedName + r":<Exception> "
+ r"does not match FormatException\."
+ r"Actual: <Closure>"));
+ });
+
+ test('throwsArgumentError', () {
+ shouldPass(() { throw new ArgumentError(''); },
+ throwsArgumentError);
+ shouldFail(() { throw new Exception(); },
+ throwsArgumentError,
+ matches(
+ r"Expected: throws an exception which matches ArgumentError +"
+ r"But: exception " + _minifiedName + r":<Exception> "
+ r"does not match ArgumentError\."
+ r"Actual: <Closure>"));
+ });
+
+ test('throwsRangeError', () {
+ shouldPass(() { throw new RangeError(0); },
+ throwsRangeError);
+ shouldFail(() { throw new Exception(); },
+ throwsRangeError,
+ matches(
+ r"Expected: throws an exception which matches RangeError +"
+ r"But: exception " + _minifiedName + r":<Exception> "
+ r"does not match RangeError\."
+ r"Actual: <Closure(: \(dynamic\) => dynamic)?>"));
+ });
+
+ test('throwsNoSuchMethodError', () {
+ shouldPass(() { throw new NoSuchMethodError(null, '', null, null); },
+ throwsNoSuchMethodError);
+ shouldFail(() { throw new Exception(); },
+ throwsNoSuchMethodError,
+ matches(
+ r"Expected: throws an exception which matches NoSuchMethodError +"
+ r"But: exception " + _minifiedName + r":<Exception> "
+ r"does not match NoSuchMethodError\."
+ r"Actual: <Closure(: \(dynamic\) => dynamic)?>"));
+ });
+
+ test('throwsUnimplementedError', () {
+ shouldPass(() { throw new UnimplementedError(''); },
+ throwsUnimplementedError);
+ shouldFail(() { throw new Exception(); },
+ throwsUnimplementedError,
+ matches(
+ r"Expected: throws an exception which matches "
+ r"UnimplementedError +"
+ r"But: exception " + _minifiedName + r":<Exception> "
+ r"does not match UnimplementedError\."
+ r"Actual: <Closure(: \(dynamic\) => dynamic)?>"));
+ });
+
+ test('throwsUnsupportedError', () {
+ shouldPass(() { throw new UnsupportedError(''); },
+ throwsUnsupportedError);
+ shouldFail(() { throw new Exception(); },
+ throwsUnsupportedError,
+ matches(
+ r"Expected: throws an exception which matches UnsupportedError +"
+ r"But: exception " + _minifiedName + r":<Exception> "
+ r"does not match UnsupportedError\."
+ r"Actual: <Closure(: \(dynamic\) => dynamic)?>"));
+ });
+
+ test('throwsStateError', () {
+ shouldPass(() { throw new StateError(''); },
+ throwsStateError);
+ shouldFail(() { throw new Exception(); },
+ throwsStateError,
+ matches(
+ r"Expected: throws an exception which matches StateError +"
+ r"But: exception " + _minifiedName + r":<Exception> "
+ r"does not match StateError\."
+ r"Actual: <Closure(: \(dynamic\) => dynamic)?>"));
+ });
+ });
+
+ group('Iterable Matchers', () {
+ test('isEmpty', () {
+ var d = new SimpleIterable(0);
+ var e = new SimpleIterable(1);
+ shouldPass(d, isEmpty);
+ shouldFail(e, isEmpty,
+ matches(r"Expected: empty +But: was " + _minifiedName + r":\[1\]\."));
+ });
+
+ test('contains', () {
+ var d = new SimpleIterable(3);
+ shouldPass(d, contains(2));
+ shouldFail(d, contains(5),
+ matches(
+ r"Expected: contains <5> +"
+ r"But: was " + _minifiedName + r":\[3, 2, 1\]\."));
+ });
+ });
+
+ group('Feature Matchers', () {
+ test("Feature Matcher", () {
+ var w = new Widget();
+ w.price = 10;
+ shouldPass(w, new HasPrice(10));
+ shouldPass(w, new HasPrice(greaterThan(0)));
+ shouldFail(w, new HasPrice(greaterThan(10)),
+ matches(
+ r"Expected: Widget with a price that is a value greater than "
+ r"<10> +"
+ r"But: price was <10>\."
+ r"Actual: <Instance of '" + _minifiedName + r"'>"));
+ });
+ });
+}
diff --git a/pkg/unittest/test/matchers_test.dart b/pkg/unittest/test/matchers_test.dart
index 10592da..4e53e16 100644
--- a/pkg/unittest/test/matchers_test.dart
+++ b/pkg/unittest/test/matchers_test.dart
@@ -2,77 +2,13 @@
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
-library unittestTests;
-import 'package:unittest/unittest.dart';
import 'dart:async';
import 'dart:collection';
-part 'test_utils.dart';
-doesNotThrow() {}
-doesThrow() { throw 'X'; }
+import 'package:unittest/unittest.dart';
-class PrefixMatcher extends BaseMatcher {
- final String _prefix;
- const PrefixMatcher(this._prefix);
- bool matches(item, MatchState matchState) {
- return item is String &&
- (collapseWhitespace(item)).startsWith(collapseWhitespace(_prefix));
- }
-
- Description describe(Description description) =>
- description.add('a string starting with ').
- addDescriptionOf(collapseWhitespace(_prefix)).
- add(' ignoring whitespace');
-}
-
-class Widget {
- int price;
-}
-
-class HasPrice extends CustomMatcher {
- HasPrice(matcher) :
- super("Widget with a price that is", "price", matcher);
- featureValueOf(actual) => actual.price;
-}
-
-class SimpleIterable extends IterableBase {
- int count;
- SimpleIterable(this.count);
-
- bool contains(int val) => count < val ? false : true;
-
- bool any(bool f(element)) {
- for(var i = 0; i <= count; i++) {
- if(f(i)) return true;
- }
- return false;
- }
-
- String toString() => "<[$count]>";
-
- Iterator get iterator {
- return new SimpleIterator(count);
- }
-}
-
-class SimpleIterator implements Iterator {
- int _count;
- int _current;
-
- SimpleIterator(this._count);
-
- bool moveNext() {
- if (_count > 0) {
- _current = _count;
- _count--;
- return true;
- }
- _current = null;
- return false;
- }
-
- get current => _current;
-}
+import 'test_common.dart';
+import 'test_utils.dart';
void main() {
@@ -84,30 +20,30 @@
test('isTrue', () {
shouldPass(true, isTrue);
- shouldFail(false, isTrue, "Expected: true but: was <false>.");
+ shouldFail(false, isTrue, "Expected: true But: was <false>.");
});
test('isFalse', () {
shouldPass(false, isFalse);
- shouldFail(10, isFalse, "Expected: false but: was <10>.");
- shouldFail(true, isFalse, "Expected: false but: was <true>.");
+ shouldFail(10, isFalse, "Expected: false But: was <10>.");
+ shouldFail(true, isFalse, "Expected: false But: was <true>.");
});
test('isNull', () {
shouldPass(null, isNull);
- shouldFail(false, isNull, "Expected: null but: was <false>.");
+ shouldFail(false, isNull, "Expected: null But: was <false>.");
});
test('isNotNull', () {
shouldPass(false, isNotNull);
- shouldFail(null, isNotNull, "Expected: not null but: was <null>.");
+ shouldFail(null, isNotNull, "Expected: not null But: was <null>.");
});
test('same', () {
var a = new Map();
var b = new Map();
shouldPass(a, same(a));
- shouldFail(b, same(a), "Expected: same instance as <{}> but: was <{}>.");
+ shouldFail(b, same(a), "Expected: same instance as {} But: was {}.");
});
test('equals', () {
@@ -122,96 +58,38 @@
shouldPass(0, anything);
shouldPass(null, anything);
shouldPass(a, anything);
- shouldFail(a, isNot(anything), "Expected: not anything but: was <{}>.");
+ shouldFail(a, isNot(anything), "Expected: not anything But: was {}.");
});
test('throws', () {
shouldFail(doesNotThrow, throws,
- "Expected: throws an exception but: no exception.");
+ matches(
+ r"Expected: throws an exception +But: no exception\."
+ r"Actual: <Closure(: \(dynamic\) => dynamic "
+ r"from Function 'doesNotThrow': static\.)?>"));
shouldPass(doesThrow, throws);
shouldFail(true, throws,
- "Expected: throws an exception but: not a Function or Future.");
+ "Expected: throws an exception But: not a Function or Future. "
+ "Actual: <true>");
});
test('throwsA', () {
shouldPass(doesThrow, throwsA(equals('X')));
shouldFail(doesThrow, throwsA(equals('Y')),
- "Expected: throws an exception which matches 'Y' "
- "but: exception 'X' does not match 'Y'.");
- });
-
- test('throwsFormatException', () {
- shouldPass(() { throw new FormatException(''); },
- throwsFormatException);
- shouldFail(() { throw new Exception(); },
- throwsFormatException,
- "Expected: throws an exception which matches FormatException "
- "but: exception <Exception> does not match FormatException.");
- });
-
- test('throwsArgumentError', () {
- shouldPass(() { throw new ArgumentError(''); },
- throwsArgumentError);
- shouldFail(() { throw new Exception(); },
- throwsArgumentError,
- "Expected: throws an exception which matches ArgumentError "
- "but: exception <Exception> does not match "
- "ArgumentError.");
- });
-
- test('throwsRangeError', () {
- shouldPass(() { throw new RangeError(0); },
- throwsRangeError);
- shouldFail(() { throw new Exception(); },
- throwsRangeError,
- "Expected: throws an exception which matches RangeError "
- "but: exception <Exception> does not match RangeError.");
- });
-
- test('throwsNoSuchMethodError', () {
- shouldPass(() { throw new NoSuchMethodError(null, '', null, null); },
- throwsNoSuchMethodError);
- shouldFail(() { throw new Exception(); },
- throwsNoSuchMethodError,
- "Expected: throws an exception which matches NoSuchMethodError "
- "but: exception <Exception> does not match "
- "NoSuchMethodError.");
- });
-
- test('throwsUnimplementedError', () {
- shouldPass(() { throw new UnimplementedError(''); },
- throwsUnimplementedError);
- shouldFail(() { throw new Exception(); },
- throwsUnimplementedError,
- "Expected: throws an exception which matches UnimplementedError "
- "but: exception <Exception> does not match "
- "UnimplementedError.");
- });
-
- test('throwsUnsupportedError', () {
- shouldPass(() { throw new UnsupportedError(''); },
- throwsUnsupportedError);
- shouldFail(() { throw new Exception(); },
- throwsUnsupportedError,
- "Expected: throws an exception which matches UnsupportedError "
- "but: exception <Exception> does not match "
- "UnsupportedError.");
- });
-
- test('throwsStateError', () {
- shouldPass(() { throw new StateError(''); },
- throwsStateError);
- shouldFail(() { throw new Exception(); },
- throwsStateError,
- "Expected: throws an exception which matches StateError "
- "but: exception <Exception> does not match "
- "StateError.");
+ matches(
+ r"Expected: throws an exception which matches 'Y' +"
+ r"But: exception 'X' does not match 'Y'\."
+ r"Actual: <Closure(: \(dynamic\) => dynamic "
+ r"from Function 'doesThrow': static\.)?>"));
});
test('returnsNormally', () {
shouldPass(doesNotThrow, returnsNormally);
shouldFail(doesThrow, returnsNormally,
- "Expected: return normally but: threw 'X'.");
+ matches(
+ r"Expected: return normally +But: threw 'X'\."
+ r"Actual: <Closure(: \(dynamic\) => dynamic "
+ r"from Function 'doesThrow': static\.)?>"));
});
test('hasLength', () {
@@ -221,41 +99,44 @@
shouldPass(b, hasLength(0));
shouldPass('a', hasLength(1));
shouldFail(0, hasLength(0), new PrefixMatcher(
- "Expected: an object with length of <0> "
- "but: was <0> has no length property."));
+ "Expected: an object with length of <0> "
+ "But: had no length property."
+ "Actual: <0>"));
b.add(0);
shouldPass(b, hasLength(1));
shouldFail(b, hasLength(2),
- "Expected: an object with length of <2> "
- "but: was <[0]> with length of <1>.");
+ "Expected: an object with length of <2> "
+ "But: had length of <1>. "
+ "Actual: [0]");
b.add(0);
shouldFail(b, hasLength(1),
- "Expected: an object with length of <1> "
- "but: was <[0, 0]> with length of <2>.");
+ "Expected: an object with length of <1> "
+ "But: had length of <2>. "
+ "Actual: [0, 0]");
shouldPass(b, hasLength(2));
});
test('scalar type mismatch', () {
shouldFail('error', equals(5.1),
- matches("^Expected: <5\.1>"
- " but: was .*:'error' \\(not type .*\\)\.\$"));
+ "Expected: <5.1> "
+ "But: was 'error'.");
});
test('nested type mismatch', () {
shouldFail(['error'], equals([5.1]),
- matches(r"^Expected: <\[5\.1\]>"
- " but: expected double:<5\.1> "
- "but was .*:'error' mismatch at position 0\.\$"));
+ "Expected: [5.1] "
+ "But: expected <5.1> but was 'error' mismatch at position 0. "
+ "Actual: ['error']");
});
test('doubly-nested type mismatch', () {
shouldFail([['error']], equals([[5.1]]),
- matches(r"^Expected: <\[\[5\.1\]\]>"
- " but: expected double:<5\.1> "
- "but was .*:'error' mismatch at position 0 "
- "mismatch at position 0\.\$"));
+ "Expected: [[5.1]] "
+ "But: expected <5.1> but was 'error' "
+ "mismatch at position 0 mismatch at position 0. "
+ "Actual: [['error']]");
});
});
@@ -264,64 +145,64 @@
test('greaterThan', () {
shouldPass(10, greaterThan(9));
shouldFail(9, greaterThan(10),
- "Expected: a value greater than <10> but: was <9>.");
+ "Expected: a value greater than <10> But: was <9>.");
});
test('greaterThanOrEqualTo', () {
shouldPass(10, greaterThanOrEqualTo(10));
shouldFail(9, greaterThanOrEqualTo(10),
- "Expected: a value greater than or equal to <10> but: was <9>.");
+ "Expected: a value greater than or equal to <10> But: was <9>.");
});
test('lessThan', () {
shouldFail(10, lessThan(9), "Expected: a value less than <9> "
- "but: was <10>.");
+ "But: was <10>.");
shouldPass(9, lessThan(10));
});
test('lessThanOrEqualTo', () {
shouldPass(10, lessThanOrEqualTo(10));
shouldFail(11, lessThanOrEqualTo(10),
- "Expected: a value less than or equal to <10> but: was <11>.");
+ "Expected: a value less than or equal to <10> But: was <11>.");
});
test('isZero', () {
shouldPass(0, isZero);
- shouldFail(1, isZero, "Expected: a value equal to <0> but: was <1>.");
+ shouldFail(1, isZero, "Expected: a value equal to <0> But: was <1>.");
});
test('isNonZero', () {
shouldFail(0, isNonZero, "Expected: a value not equal to <0> "
- "but: was <0>.");
+ "But: was <0>.");
shouldPass(1, isNonZero);
});
test('isPositive', () {
shouldFail(-1, isPositive, "Expected: a positive value "
- "but: was <-1>.");
+ "But: was <-1>.");
shouldFail(0, isPositive, "Expected: a positive value "
- "but: was <0>.");
+ "But: was <0>.");
shouldPass(1, isPositive);
});
test('isNegative', () {
shouldPass(-1, isNegative);
shouldFail(0, isNegative,
- "Expected: a negative value but: was <0>.");
+ "Expected: a negative value But: was <0>.");
});
test('isNonPositive', () {
shouldPass(-1, isNonPositive);
shouldPass(0, isNonPositive);
shouldFail(1, isNonPositive,
- "Expected: a non-positive value but: was <1>.");
+ "Expected: a non-positive value But: was <1>.");
});
test('isNonNegative', () {
shouldPass(1, isNonNegative);
shouldPass(0, isNonNegative);
shouldFail(-1, isNonNegative,
- "Expected: a non-negative value but: was <-1>.");
+ "Expected: a non-negative value But: was <-1>.");
});
test('closeTo', () {
@@ -330,38 +211,40 @@
shouldPass(1, closeTo(0, 1));
shouldFail(1.001, closeTo(0, 1),
"Expected: a numeric value within <1> of <0> "
- "but: <1.001> differed by <1.001>.");
+ "But: differed by <1.001>. "
+ "Actual: <1.001>");
shouldFail(-1.001, closeTo(0, 1),
"Expected: a numeric value within <1> of <0> "
- "but: <-1.001> differed by <1.001>.");
+ "But: differed by <1.001>. "
+ "Actual: <-1.001>");
});
test('inInclusiveRange', () {
shouldFail(-1, inInclusiveRange(0,2),
"Expected: be in range from 0 (inclusive) to 2 (inclusive) "
- "but: was <-1>.");
+ "But: was <-1>.");
shouldPass(0, inInclusiveRange(0,2));
shouldPass(1, inInclusiveRange(0,2));
shouldPass(2, inInclusiveRange(0,2));
shouldFail(3, inInclusiveRange(0,2),
"Expected: be in range from 0 (inclusive) to 2 (inclusive) "
- "but: was <3>.");
+ "But: was <3>.");
});
test('inExclusiveRange', () {
shouldFail(0, inExclusiveRange(0,2),
"Expected: be in range from 0 (exclusive) to 2 (exclusive) "
- "but: was <0>.");
+ "But: was <0>.");
shouldPass(1, inExclusiveRange(0,2));
shouldFail(2, inExclusiveRange(0,2),
"Expected: be in range from 0 (exclusive) to 2 (exclusive) "
- "but: was <2>.");
+ "But: was <2>.");
});
test('inOpenClosedRange', () {
shouldFail(0, inOpenClosedRange(0,2),
"Expected: be in range from 0 (exclusive) to 2 (inclusive) "
- "but: was <0>.");
+ "But: was <0>.");
shouldPass(1, inOpenClosedRange(0,2));
shouldPass(2, inOpenClosedRange(0,2));
});
@@ -371,7 +254,7 @@
shouldPass(1, inClosedOpenRange(0,2));
shouldFail(2, inClosedOpenRange(0,2),
"Expected: be in range from 0 (inclusive) to 2 (exclusive) "
- "but: was <2>.");
+ "But: was <2>.");
});
});
@@ -380,22 +263,22 @@
test('isEmpty', () {
shouldPass('', isEmpty);
shouldFail(null, isEmpty,
- "Expected: empty but: was <null>.");
+ "Expected: empty But: was <null>.");
shouldFail(0, isEmpty,
- "Expected: empty but: was <0>.");
- shouldFail('a', isEmpty, "Expected: empty but: was 'a'.");
+ "Expected: empty But: was <0>.");
+ shouldFail('a', isEmpty, "Expected: empty But: was 'a'.");
});
test('equalsIgnoringCase', () {
shouldPass('hello', equalsIgnoringCase('HELLO'));
shouldFail('hi', equalsIgnoringCase('HELLO'),
- "Expected: 'HELLO' ignoring case but: was 'hi'.");
+ "Expected: 'HELLO' ignoring case But: was 'hi'.");
});
test('equalsIgnoringWhitespace', () {
shouldPass(' hello world ', equalsIgnoringWhitespace('hello world'));
shouldFail(' helloworld ', equalsIgnoringWhitespace('hello world'),
- "Expected: 'hello world' ignoring whitespace but: was 'helloworld'.");
+ "Expected: 'hello world' ignoring whitespace But: was 'helloworld'.");
});
test('startsWith', () {
@@ -403,7 +286,7 @@
shouldPass('hello', startsWith('hell'));
shouldPass('hello', startsWith('hello'));
shouldFail('hello', startsWith('hello '),
- "Expected: a string starting with 'hello ' but: was 'hello'.");
+ "Expected: a string starting with 'hello ' But: was 'hello'.");
});
test('endsWith', () {
@@ -411,7 +294,7 @@
shouldPass('hello', endsWith('lo'));
shouldPass('hello', endsWith('hello'));
shouldFail('hello', endsWith(' hello'),
- "Expected: a string ending with ' hello' but: was 'hello'.");
+ "Expected: a string ending with ' hello' But: was 'hello'.");
});
test('contains', () {
@@ -421,7 +304,7 @@
shouldPass('hello', contains('hell'));
shouldPass('hello', contains('hello'));
shouldFail('hello', contains(' '),
- "Expected: contains ' ' but: was 'hello'.");
+ "Expected: contains ' ' But: was 'hello'.");
});
test('stringContainsInOrder', () {
@@ -440,29 +323,14 @@
shouldFail('goodbye cruel world',
stringContainsInOrder(['goo', 'cruel', 'bye']),
"Expected: a string containing 'goo', 'cruel', 'bye' in order "
- "but: was 'goodbye cruel world'.");
+ "But: was 'goodbye cruel world'.");
});
test('matches', () {
shouldPass('c0d', matches('[a-z][0-9][a-z]'));
shouldPass('c0d', matches(new RegExp('[a-z][0-9][a-z]')));
shouldFail('cOd', matches('[a-z][0-9][a-z]'),
- "Expected: match '[a-z][0-9][a-z]' but: was 'cOd'.");
- });
- });
-
- group('Iterable Matchers', () {
- test('isEmpty', () {
- var d = new SimpleIterable(0);
- var e = new SimpleIterable(1);
- shouldPass(d, isEmpty);
- shouldFail(e, isEmpty, "Expected: empty but: was <[1]>.");
- });
-
- test('contains', () {
- var d = new SimpleIterable(3);
- shouldPass(d, contains(2));
- shouldFail(d, contains(5), "Expected: contains <5> but: was <[3]>.");
+ "Expected: match '[a-z][0-9][a-z]' But: was 'cOd'.");
});
});
@@ -470,26 +338,27 @@
test('isEmpty', () {
shouldPass([], isEmpty);
- shouldFail([1], isEmpty, "Expected: empty but: was <[1]>.");
+ shouldFail([1], isEmpty, "Expected: empty But: was [1].");
});
test('contains', () {
var d = [1, 2];
shouldPass(d, contains(1));
- shouldFail(d, contains(0), "Expected: contains <0> but: was <[1, 2]>.");
+ shouldFail(d, contains(0), "Expected: contains <0> But: was [1, 2].");
});
test('isIn', () {
var d = [1, 2];
shouldPass(1, isIn(d));
- shouldFail(0, isIn(d), "Expected: is in <[1, 2]> but: was <0>.");
+ shouldFail(0, isIn(d), "Expected: is in [1, 2] But: was <0>.");
});
test('everyElement', () {
var d = [1, 2];
var e = [1, 1, 1];
shouldFail(d, everyElement(1),
- "Expected: every element <1> but: was <2> at position 1.");
+ "Expected: every element <1> But: position 1 was <2>. "
+ "Actual: [1, 2]");
shouldPass(e, everyElement(1));
});
@@ -498,7 +367,7 @@
var e = [1, 1, 1];
shouldPass(d, someElement(2));
shouldFail(e, someElement(2),
- "Expected: some element <2> but: was <[1, 1, 1]>.");
+ "Expected: some element <2> But: was [1, 1, 1].");
});
test('orderedEquals', () {
@@ -506,22 +375,26 @@
var d = [1, 2];
shouldPass(d, orderedEquals([1, 2]));
shouldFail(d, orderedEquals([2, 1]),
- "Expected: equals <[2, 1]> ordered "
- "but: expected <2> but was <1> mismatch at position 0.");
+ "Expected: equals [2, 1] ordered "
+ "But: expected <2> but was <1> mismatch at position 0. "
+ "Actual: [1, 2]");
});
test('unorderedEquals', () {
var d = [1, 2];
shouldPass(d, unorderedEquals([2, 1]));
shouldFail(d, unorderedEquals([1]),
- "Expected: equals <[1]> unordered "
- "but: has too many elements (2 > 1).");
+ "Expected: equals [1] unordered "
+ "But: has too many elements (2 > 1). "
+ "Actual: [1, 2]");
shouldFail(d, unorderedEquals([3, 2, 1]),
- "Expected: equals <[3, 2, 1]> unordered "
- "but: has too few elements (2 < 3).");
+ "Expected: equals [3, 2, 1] unordered "
+ "But: has too few elements (2 < 3). "
+ "Actual: [1, 2]");
shouldFail(d, unorderedEquals([3, 1]),
- "Expected: equals <[3, 1]> unordered "
- "but: has no match for element <3> at position 0.");
+ "Expected: equals [3, 1] unordered "
+ "But: has no match for element <3> at position 0. "
+ "Actual: [1, 2]");
});
test('pairwise compare', () {
@@ -530,19 +403,23 @@
var e = [1, 4, 9];
shouldFail('x', pairwiseCompare(e, (e,a) => a <= e,
"less than or equal"),
- "Expected: pairwise less than or equal <[1, 4, 9]> but: "
- "not an Iterable.");
+ "Expected: pairwise less than or equal [1, 4, 9] "
+ "But: not an Iterable. "
+ "Actual: 'x'");
shouldFail(c, pairwiseCompare(e, (e,a) => a <= e, "less than or equal"),
- "Expected: pairwise less than or equal <[1, 4, 9]> but: "
- "length was 2 instead of 3.");
+ "Expected: pairwise less than or equal [1, 4, 9] "
+ "But: length was 2 instead of 3. "
+ "Actual: [1, 2]");
shouldPass(d, pairwiseCompare(e, (e,a) => a <= e, "less than or equal"));
shouldFail(d, pairwiseCompare(e, (e,a) => a < e, "less than"),
- "Expected: pairwise less than <[1, 4, 9]> but: "
- "<1> not less than <1> at position 0.");
+ "Expected: pairwise less than [1, 4, 9] "
+ "But: <1> not less than <1> at position 0. "
+ "Actual: [1, 2, 3]");
shouldPass(d, pairwiseCompare(e, (e,a) => a * a == e, "square root of"));
shouldFail(d, pairwiseCompare(e, (e,a) => a + a == e, "double"),
- "Expected: pairwise double <[1, 4, 9]> but: "
- "<1> not double <1> at position 0.");
+ "Expected: pairwise double [1, 4, 9] "
+ "But: <1> not double <1> at position 0. "
+ "Actual: [1, 2, 3]");
});
});
@@ -553,7 +430,7 @@
shouldPass({}, isEmpty);
shouldPass(a, isEmpty);
a['foo'] = 'bar';
- shouldFail(a, isEmpty, "Expected: empty but: was <{foo: bar}>.");
+ shouldFail(a, isEmpty, "Expected: empty But: was {'foo': 'bar'}.");
});
test('equals', () {
@@ -565,7 +442,8 @@
c['bar'] = 'foo';
shouldPass(a, equals(b));
shouldFail(b, equals(c),
- "Expected: <{bar: foo}> but: missing map key 'bar'.");
+ "Expected: {'bar': 'foo'} But: missing map key 'bar'. "
+ "Actual: {'foo': 'bar'}");
});
test('equals with different lengths', () {
@@ -578,23 +456,29 @@
c['bar'] = 'foo';
c['barrista'] = 'caffeine';
shouldFail(a, equals(b),
- "Expected: <{foo: bar, bar: foo}> "
- "but: different map lengths; missing map key 'bar'.");
+ "Expected: {'foo': 'bar', 'bar': 'foo'} "
+ "But: different map lengths; missing map key 'bar'. "
+ "Actual: {'foo': 'bar'}");
shouldFail(b, equals(a),
- "Expected: <{foo: bar}> "
- "but: different map lengths; extra map key 'bar'.");
+ "Expected: {'foo': 'bar'} "
+ "But: different map lengths; extra map key 'bar'. "
+ "Actual: {'foo': 'bar', 'bar': 'foo'}");
shouldFail(b, equals(c),
- "Expected: <{bar: foo, barrista: caffeine}> "
- "but: missing map key 'barrista'.");
+ "Expected: {'bar': 'foo', 'barrista': 'caffeine'} "
+ "But: missing map key 'barrista'. "
+ "Actual: {'foo': 'bar', 'bar': 'foo'}");
shouldFail(c, equals(b),
- "Expected: <{foo: bar, bar: foo}> "
- "but: missing map key 'foo'.");
+ "Expected: {'foo': 'bar', 'bar': 'foo'} "
+ "But: missing map key 'foo'. "
+ "Actual: {'bar': 'foo', 'barrista': 'caffeine'}");
shouldFail(a, equals(c),
- "Expected: <{bar: foo, barrista: caffeine}> "
- "but: different map lengths; missing map key 'bar'.");
+ "Expected: {'bar': 'foo', 'barrista': 'caffeine'} "
+ "But: different map lengths; missing map key 'bar'. "
+ "Actual: {'foo': 'bar'}");
shouldFail(c, equals(a),
- "Expected: <{foo: bar}> "
- "but: different map lengths; missing map key 'foo'.");
+ "Expected: {'foo': 'bar'} "
+ "But: different map lengths; missing map key 'foo'. "
+ "Actual: {'bar': 'foo', 'barrista': 'caffeine'}");
});
test('contains', () {
@@ -603,9 +487,9 @@
var b = new Map();
shouldPass(a, contains('foo'));
shouldFail(b, contains('foo'),
- "Expected: contains 'foo' but: was <{}>.");
+ "Expected: contains 'foo' But: was {}.");
shouldFail(10, contains('foo'),
- "Expected: contains 'foo' but: was <10>.");
+ "Expected: contains 'foo' But: was <10>.");
});
test('containsValue', () {
@@ -613,7 +497,7 @@
a['foo'] = 'bar';
shouldPass(a, containsValue('bar'));
shouldFail(a, containsValue('ba'),
- "Expected: contains value 'ba' but: was <{foo: bar}>.");
+ "Expected: contains value 'ba' But: was {'foo': 'bar'}.");
});
test('containsPair', () {
@@ -622,10 +506,12 @@
shouldPass(a, containsPair('foo', 'bar'));
shouldFail(a, containsPair('foo', 'ba'),
"Expected: contains pair 'foo' => 'ba' "
- "but: contains key 'foo' but with value was 'bar'.");
+ "But: contains key 'foo' but with value was 'bar'. "
+ "Actual: {'foo': 'bar'}");
shouldFail(a, containsPair('fo', 'bar'),
"Expected: contains pair 'fo' => 'bar' "
- "but: <{foo: bar}> doesn't contain key 'fo'.");
+ "But: doesn't contain key 'fo'. "
+ "Actual: {'foo': 'bar'}");
});
test('hasLength', () {
@@ -635,7 +521,8 @@
shouldPass(a, hasLength(1));
shouldFail(b, hasLength(1),
"Expected: an object with length of <1> "
- "but: was <{}> with length of <0>.");
+ "But: had length of <0>. "
+ "Actual: {}");
});
});
@@ -643,7 +530,7 @@
test('anyOf', () {
shouldFail(0, anyOf([equals(1), equals(2)]),
- "Expected: (<1> or <2>) but: was <0>.");
+ "Expected: (<1> or <2>) But: was <0>.");
shouldPass(1, anyOf([equals(1), equals(2)]));
});
@@ -651,7 +538,7 @@
shouldPass(1, allOf([lessThan(10), greaterThan(0)]));
shouldFail(-1, allOf([lessThan(10), greaterThan(0)]),
"Expected: (a value less than <10> and a value greater than <0>) "
- "but: a value greater than <0> was <-1>.");
+ "But: was <-1> (wasn't a value greater than <0>).");
});
});
@@ -711,7 +598,7 @@
var completer = new Completer();
completer.completeError('X');
shouldFail(completer.future, throwsA(equals('Y')),
- "Expected: 'Y' but: was 'X'.",
+ "Expected: 'Y' But: was 'X'.",
isAsync: true);
});
});
@@ -719,21 +606,9 @@
group('Predicate Matchers', () {
test('isInstanceOf', () {
shouldFail(0, predicate((x) => x is String, "an instance of String"),
- "Expected: an instance of String but: was <0>.");
+ "Expected: an instance of String But: was <0>.");
shouldPass('cow', predicate((x) => x is String, "an instance of String"));
});
});
-
- group('Feature Matchers', () {
- test("Feature Matcher", () {
- var w = new Widget();
- w.price = 10;
- shouldPass(w, new HasPrice(10));
- shouldPass(w, new HasPrice(greaterThan(0)));
- shouldFail(w, new HasPrice(greaterThan(10)),
- 'Expected: Widget with a price that is a value greater than <10> '
- 'but: price was <10>.');
- });
- });
}
diff --git a/pkg/unittest/test/matchers_unminified_test.dart b/pkg/unittest/test/matchers_unminified_test.dart
new file mode 100644
index 0000000..7435a0c
--- /dev/null
+++ b/pkg/unittest/test/matchers_unminified_test.dart
@@ -0,0 +1,132 @@
+// 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.
+
+// This file is for matcher tests that rely on the names of various Dart types.
+// These tests will fail when run in minified dart2js, since the names will be
+// mangled. A version of this file that works in minified dart2js is in
+// matchers_minified_test.dart.
+
+import 'package:unittest/unittest.dart';
+
+import 'test_common.dart';
+import 'test_utils.dart';
+
+void main() {
+ initUtils();
+
+ group('Core matchers', () {
+ test('throwsFormatException', () {
+ shouldPass(() { throw new FormatException(''); },
+ throwsFormatException);
+ shouldFail(() { throw new Exception(); },
+ throwsFormatException,
+ matches(
+ r"Expected: throws an exception which matches FormatException +"
+ r"But: exception \?:<Exception> does not match FormatException\."
+ r"Actual: <Closure(: \(dynamic\) => dynamic)?>"));
+ });
+
+ test('throwsArgumentError', () {
+ shouldPass(() { throw new ArgumentError(''); },
+ throwsArgumentError);
+ shouldFail(() { throw new Exception(); },
+ throwsArgumentError,
+ matches(
+ r"Expected: throws an exception which matches ArgumentError +"
+ r"But: exception \?:<Exception> does not match "
+ r"ArgumentError\."
+ r"Actual: <Closure(: \(dynamic\) => dynamic)?>"));
+ });
+
+ test('throwsRangeError', () {
+ shouldPass(() { throw new RangeError(0); },
+ throwsRangeError);
+ shouldFail(() { throw new Exception(); },
+ throwsRangeError,
+ matches(
+ r"Expected: throws an exception which matches RangeError +"
+ r"But: exception \?:<Exception> does not match RangeError\."
+ r"Actual: <Closure(: \(dynamic\) => dynamic)?>"));
+ });
+
+ test('throwsNoSuchMethodError', () {
+ shouldPass(() { throw new NoSuchMethodError(null, '', null, null); },
+ throwsNoSuchMethodError);
+ shouldFail(() { throw new Exception(); },
+ throwsNoSuchMethodError,
+ matches(
+ r"Expected: throws an exception which matches NoSuchMethodError +"
+ r"But: exception \?:<Exception> does not match "
+ r"NoSuchMethodError\."
+ r"Actual: <Closure(: \(dynamic\) => dynamic)?>"));
+ });
+
+ test('throwsUnimplementedError', () {
+ shouldPass(() { throw new UnimplementedError(''); },
+ throwsUnimplementedError);
+ shouldFail(() { throw new Exception(); },
+ throwsUnimplementedError,
+ matches(
+ r"Expected: throws an exception which matches "
+ r"UnimplementedError +"
+ r"But: exception \?:<Exception> does not match "
+ r"UnimplementedError\."
+ r"Actual: <Closure(: \(dynamic\) => dynamic)?>"));
+ });
+
+ test('throwsUnsupportedError', () {
+ shouldPass(() { throw new UnsupportedError(''); },
+ throwsUnsupportedError);
+ shouldFail(() { throw new Exception(); },
+ throwsUnsupportedError,
+ matches(
+ r"Expected: throws an exception which matches UnsupportedError +"
+ r"But: exception \?:<Exception> does not match "
+ r"UnsupportedError\."
+ r"Actual: <Closure(: \(dynamic\) => dynamic)?>"));
+ });
+
+ test('throwsStateError', () {
+ shouldPass(() { throw new StateError(''); },
+ throwsStateError);
+ shouldFail(() { throw new Exception(); },
+ throwsStateError,
+ matches(
+ r"Expected: throws an exception which matches StateError +"
+ r"But: exception \?:<Exception> does not match "
+ r"StateError\."
+ r"Actual: <Closure(: \(dynamic\) => dynamic)?>"));
+ });
+ });
+
+ group('Iterable Matchers', () {
+ test('isEmpty', () {
+ var d = new SimpleIterable(0);
+ var e = new SimpleIterable(1);
+ shouldPass(d, isEmpty);
+ shouldFail(e, isEmpty, "Expected: empty But: was SimpleIterable:[1].");
+ });
+
+ test('contains', () {
+ var d = new SimpleIterable(3);
+ shouldPass(d, contains(2));
+ shouldFail(d, contains(5),
+ "Expected: contains <5> "
+ "But: was SimpleIterable:[3, 2, 1].");
+ });
+ });
+
+ group('Feature Matchers', () {
+ test("Feature Matcher", () {
+ var w = new Widget();
+ w.price = 10;
+ shouldPass(w, new HasPrice(10));
+ shouldPass(w, new HasPrice(greaterThan(0)));
+ shouldFail(w, new HasPrice(greaterThan(10)),
+ "Expected: Widget with a price that is a value greater than <10> "
+ "But: price was <10>. "
+ "Actual: <Instance of 'Widget'>");
+ });
+ });
+}
diff --git a/pkg/unittest/test/pretty_print_minified_test.dart b/pkg/unittest/test/pretty_print_minified_test.dart
new file mode 100644
index 0000000..16c5cd6
--- /dev/null
+++ b/pkg/unittest/test/pretty_print_minified_test.dart
@@ -0,0 +1,61 @@
+// 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.
+
+// This file is for pretty-print tests that rely on the names of various Dart
+// types. These tests normally fail when run in minified dart2js, since the
+// names will be mangled. This version of the file is modified to expect
+// minified names.
+
+import 'dart:collection';
+
+import 'package:unittest/src/pretty_print.dart';
+import 'package:unittest/unittest.dart';
+
+class DefaultToString {}
+
+class CustomToString {
+ String toString() => "string representation";
+}
+
+class _PrivateName {
+ String toString() => "string representation";
+}
+
+class _PrivateNameIterable extends IterableMixin {
+ Iterator get iterator => [1, 2, 3].iterator;
+}
+
+// A regexp fragment matching a minified name.
+final _minifiedName = r"[A-Za-z0-9]{1,3}";
+
+void main() {
+ group('with an object', () {
+ test('with a default [toString]', () {
+ expect(prettyPrint(new DefaultToString()),
+ matches(r"<Instance of '" + _minifiedName + r"'>"));
+ });
+
+ test('with a custom [toString]', () {
+ expect(prettyPrint(new CustomToString()),
+ matches(_minifiedName + r':<string representation>'));
+ });
+
+ test('with a custom [toString] and a private name', () {
+ expect(prettyPrint(new _PrivateName()),
+ matches(_minifiedName + r':<string representation>'));
+ });
+ });
+
+ group('with an iterable', () {
+ test("that's not a list", () {
+ expect(prettyPrint([1, 2, 3, 4].map((n) => n * 2)),
+ matches(_minifiedName + r":\[2, 4, 6, 8\]"));
+ });
+
+ test("that's not a list and has a private name", () {
+ expect(prettyPrint(new _PrivateNameIterable()),
+ matches(_minifiedName + r":\[1, 2, 3\]"));
+ });
+ });
+}
diff --git a/pkg/unittest/test/pretty_print_test.dart b/pkg/unittest/test/pretty_print_test.dart
new file mode 100644
index 0000000..e5cd2e2
--- /dev/null
+++ b/pkg/unittest/test/pretty_print_test.dart
@@ -0,0 +1,181 @@
+// 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:unittest/src/pretty_print.dart';
+import 'package:unittest/unittest.dart';
+
+void main() {
+ test('with primitive objects', () {
+ expect(prettyPrint(12), equals('<12>'));
+ expect(prettyPrint(12.13), equals('<12.13>'));
+ expect(prettyPrint(true), equals('<true>'));
+ expect(prettyPrint(null), equals('<null>'));
+ expect(prettyPrint(() => 12),
+ matches(r'<Closure(: \(dynamic\) => dynamic)?>'));
+ });
+
+ group('with a string', () {
+ test('containing simple characters', () {
+ expect(prettyPrint('foo'), equals("'foo'"));
+ });
+
+ test('containing newlines', () {
+ expect(prettyPrint('foo\nbar\nbaz'), equals(
+ "'foo\\n'\n"
+ " 'bar\\n'\n"
+ " 'baz'"));
+ });
+
+ test('containing escapable characters', () {
+ expect(prettyPrint("foo\rbar\tbaz'qux"),
+ equals("'foo\\rbar\\tbaz\\'qux'"));
+ });
+ });
+
+ group('with an iterable', () {
+ test('containing primitive objects', () {
+ expect(prettyPrint([1, true, 'foo']), equals("[1, true, 'foo']"));
+ });
+
+ test('containing a multiline string', () {
+ expect(prettyPrint(['foo', 'bar\nbaz\nbip', 'qux']), equals("[\n"
+ " 'foo',\n"
+ " 'bar\\n'\n"
+ " 'baz\\n'\n"
+ " 'bip',\n"
+ " 'qux'\n"
+ "]"));
+ });
+
+ test("that's under maxLineLength", () {
+ expect(prettyPrint([0, 1, 2, 3, 4, 5, 6, 7, 8, 9], maxLineLength: 30),
+ equals("[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]"));
+ });
+
+ test("that's over maxLineLength", () {
+ expect(prettyPrint([0, 1, 2, 3, 4, 5, 6, 7, 8, 9], maxLineLength: 29),
+ equals("[\n"
+ " 0,\n"
+ " 1,\n"
+ " 2,\n"
+ " 3,\n"
+ " 4,\n"
+ " 5,\n"
+ " 6,\n"
+ " 7,\n"
+ " 8,\n"
+ " 9\n"
+ "]"));
+ });
+
+ test("factors indentation into maxLineLength", () {
+ expect(prettyPrint([
+ "foo\nbar",
+ [0, 1, 2, 3, 4, 5, 6, 7, 8, 9],
+ ], maxLineLength: 30), equals("[\n"
+ " 'foo\\n'\n"
+ " 'bar',\n"
+ " [\n"
+ " 0,\n"
+ " 1,\n"
+ " 2,\n"
+ " 3,\n"
+ " 4,\n"
+ " 5,\n"
+ " 6,\n"
+ " 7,\n"
+ " 8,\n"
+ " 9\n"
+ " ]\n"
+ "]"));
+ });
+
+ test("that's under maxItems", () {
+ expect(prettyPrint([0, 1, 2, 3, 4, 5, 6, 7, 8, 9], maxItems: 10),
+ equals("[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]"));
+ });
+
+ test("that's over maxItems", () {
+ expect(prettyPrint([0, 1, 2, 3, 4, 5, 6, 7, 8, 9], maxItems: 9),
+ equals("[0, 1, 2, 3, 4, 5, 6, 7, ...]"));
+ });
+
+ test("that's recursive", () {
+ var list = [1, 2, 3];
+ list.add(list);
+ expect(prettyPrint(list), equals("[1, 2, 3, (recursive)]"));
+ });
+ });
+
+ group("with a map", () {
+ test('containing primitive objects', () {
+ expect(prettyPrint({'foo': 1, 'bar': true}),
+ equals("{'foo': 1, 'bar': true}"));
+ });
+
+ test('containing a multiline string key', () {
+ expect(prettyPrint({'foo\nbar': 1, 'bar': true}), equals("{\n"
+ " 'foo\\n'\n"
+ " 'bar': 1,\n"
+ " 'bar': true\n"
+ "}"));
+ });
+
+ test('containing a multiline string value', () {
+ expect(prettyPrint({'foo': 'bar\nbaz', 'qux': true}), equals("{\n"
+ " 'foo': 'bar\\n'\n"
+ " 'baz',\n"
+ " 'qux': true\n"
+ "}"));
+ });
+
+ test('containing a multiline string key/value pair', () {
+ expect(prettyPrint({'foo\nbar': 'baz\nqux'}), equals("{\n"
+ " 'foo\\n'\n"
+ " 'bar': 'baz\\n'\n"
+ " 'qux'\n"
+ "}"));
+ });
+
+ test("that's under maxLineLength", () {
+ expect(prettyPrint({'0': 1, '2': 3, '4': 5, '6': 7}, maxLineLength: 32),
+ equals("{'0': 1, '2': 3, '4': 5, '6': 7}"));
+ });
+
+ test("that's over maxLineLength", () {
+ expect(prettyPrint({'0': 1, '2': 3, '4': 5, '6': 7}, maxLineLength: 31),
+ equals("{\n"
+ " '0': 1,\n"
+ " '2': 3,\n"
+ " '4': 5,\n"
+ " '6': 7\n"
+ "}"));
+ });
+
+ test("factors indentation into maxLineLength", () {
+ expect(prettyPrint(["foo\nbar", {'0': 1, '2': 3, '4': 5, '6': 7}],
+ maxLineLength: 32),
+ equals("[\n"
+ " 'foo\\n'\n"
+ " 'bar',\n"
+ " {\n"
+ " '0': 1,\n"
+ " '2': 3,\n"
+ " '4': 5,\n"
+ " '6': 7\n"
+ " }\n"
+ "]"));
+ });
+
+ test("that's under maxItems", () {
+ expect(prettyPrint({'0': 1, '2': 3, '4': 5, '6': 7}, maxItems: 4),
+ equals("{'0': 1, '2': 3, '4': 5, '6': 7}"));
+ });
+
+ test("that's over maxItems", () {
+ expect(prettyPrint({'0': 1, '2': 3, '4': 5, '6': 7}, maxItems: 3),
+ equals("{'0': 1, '2': 3, ...}"));
+ });
+ });
+}
diff --git a/pkg/unittest/test/pretty_print_unminified_test.dart b/pkg/unittest/test/pretty_print_unminified_test.dart
new file mode 100644
index 0000000..4417bcb
--- /dev/null
+++ b/pkg/unittest/test/pretty_print_unminified_test.dart
@@ -0,0 +1,58 @@
+// 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.
+
+// This file is for pretty-print tests that rely on the names of various Dart
+// types. These tests will fail when run in minified dart2js, since the names
+// will be mangled. A version of this file that works in minified dart2js is in
+// pretty_print_minified_test.dart.
+
+import 'dart:collection';
+
+import 'package:unittest/src/pretty_print.dart';
+import 'package:unittest/unittest.dart';
+
+class DefaultToString {}
+
+class CustomToString {
+ String toString() => "string representation";
+}
+
+class _PrivateName {
+ String toString() => "string representation";
+}
+
+class _PrivateNameIterable extends IterableMixin {
+ Iterator get iterator => [1, 2, 3].iterator;
+}
+
+void main() {
+ group('with an object', () {
+ test('with a default [toString]', () {
+ expect(prettyPrint(new DefaultToString()),
+ equals("<Instance of 'DefaultToString'>"));
+ });
+
+ test('with a custom [toString]', () {
+ expect(prettyPrint(new CustomToString()),
+ equals('CustomToString:<string representation>'));
+ });
+
+ test('with a custom [toString] and a private name', () {
+ expect(prettyPrint(new _PrivateName()),
+ equals('?:<string representation>'));
+ });
+ });
+
+ group('with an iterable', () {
+ test("that's not a list", () {
+ expect(prettyPrint([1, 2, 3, 4].map((n) => n * 2)),
+ equals("MappedListIterable:[2, 4, 6, 8]"));
+ });
+
+ test("that's not a list and has a private name", () {
+ expect(prettyPrint(new _PrivateNameIterable()),
+ equals("?:[1, 2, 3]"));
+ });
+ });
+}
diff --git a/pkg/unittest/test/test_common.dart b/pkg/unittest/test/test_common.dart
new file mode 100644
index 0000000..8631768
--- /dev/null
+++ b/pkg/unittest/test/test_common.dart
@@ -0,0 +1,59 @@
+// 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.
+
+library test_common;
+
+import 'dart:collection';
+
+import 'package:unittest/unittest.dart';
+
+class Widget {
+ int price;
+}
+
+class HasPrice extends CustomMatcher {
+ HasPrice(matcher) :
+ super("Widget with a price that is", "price", matcher);
+ featureValueOf(actual) => actual.price;
+}
+
+class SimpleIterable extends IterableBase {
+ int count;
+ SimpleIterable(this.count);
+
+ bool contains(int val) => count < val ? false : true;
+
+ bool any(bool f(element)) {
+ for(var i = 0; i <= count; i++) {
+ if(f(i)) return true;
+ }
+ return false;
+ }
+
+ String toString() => "<[$count]>";
+
+ Iterator get iterator {
+ return new SimpleIterator(count);
+ }
+}
+
+class SimpleIterator implements Iterator {
+ int _count;
+ int _current;
+
+ SimpleIterator(this._count);
+
+ bool moveNext() {
+ if (_count > 0) {
+ _current = _count;
+ _count--;
+ return true;
+ }
+ _current = null;
+ return false;
+ }
+
+ get current => _current;
+}
+
diff --git a/pkg/unittest/test/test_utils.dart b/pkg/unittest/test/test_utils.dart
index d783665..f0b276d 100644
--- a/pkg/unittest/test/test_utils.dart
+++ b/pkg/unittest/test/test_utils.dart
@@ -2,7 +2,11 @@
// 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 unittestTests;
+library test_utils;
+
+import 'package:unittest/unittest.dart';
+
+import 'dart:async';
int errorCount;
String errorString;
@@ -58,3 +62,20 @@
afterTest();
}
}
+
+doesNotThrow() {}
+doesThrow() { throw 'X'; }
+
+class PrefixMatcher extends BaseMatcher {
+ final String _prefix;
+ const PrefixMatcher(this._prefix);
+ bool matches(item, MatchState matchState) {
+ return item is String &&
+ (collapseWhitespace(item)).startsWith(collapseWhitespace(_prefix));
+ }
+
+ Description describe(Description description) =>
+ description.add('a string starting with ').
+ addDescriptionOf(collapseWhitespace(_prefix)).
+ add(' ignoring whitespace');
+}
diff --git a/pkg/unittest/test/unittest_test.dart b/pkg/unittest/test/unittest_test.dart
index 1bbfb18..cc28d9e 100644
--- a/pkg/unittest/test/unittest_test.dart
+++ b/pkg/unittest/test/unittest_test.dart
@@ -405,7 +405,7 @@
var tests = {
'single correct test': buildStatusString(1, 0, 0, 'single correct test'),
'single failing test': buildStatusString(0, 1, 0, 'single failing test',
- message: 'Expected: <5> but: was <4>.'),
+ message: 'Expected: <5> But: was <4>.'),
'exception test': buildStatusString(0, 1, 0, 'exception test',
message: 'Caught Exception: Fail.'),
'group name test': buildStatusString(2, 0, 0, 'a a::a b b'),
@@ -427,7 +427,7 @@
message: 'Callback called (2) after test case testOne has already '
'been marked as pass.:testTwo:'),
'middle exception test': buildStatusString(2, 1, 0,
- 'testOne::testTwo:Expected: false but: was <true>.:testThree'),
+ 'testOne::testTwo:Expected: false But: was <true>.:testThree'),
'async setup/teardown test': buildStatusString(2, 0, 3,
'good setup/good teardown foo1::'
'good setup/bad teardown foo2:good setup/bad teardown '
@@ -440,13 +440,13 @@
'test returning future': buildStatusString(2, 4, 0,
'successful::'
'error1:Callback called more times than expected (1).:'
- 'fail1:Expected: <false> but: was <true>.:'
+ 'fail1:Expected: <false> But: was <true>.:'
'error2:Callback called more times than expected (1).:'
'fail2:failure:'
'foo5'),
'test returning future using runAsync': buildStatusString(2, 4, 0,
'successful::'
- 'fail1:Expected: <false> but: was <true>.:'
+ 'fail1:Expected: <false> But: was <true>.:'
'error1:Callback called more times than expected (1).:'
'fail2:failure:'
'error2:Callback called more times than expected (1).:'
diff --git a/runtime/bin/gen_snapshot.cc b/runtime/bin/gen_snapshot.cc
index 41d71f1..5e5b61a 100644
--- a/runtime/bin/gen_snapshot.cc
+++ b/runtime/bin/gen_snapshot.cc
@@ -267,6 +267,17 @@
}
+static Builtin::BuiltinLibraryId BuiltinId(const char* url) {
+ if (DartUtils::IsDartBuiltinLibURL(url)) {
+ return Builtin::kBuiltinLibrary;
+ }
+ if (DartUtils::IsDartIOLibURL(url)) {
+ return Builtin::kIOLibrary;
+ }
+ return Builtin::kInvalidLibrary;
+}
+
+
static Dart_Handle CreateSnapshotLibraryTagHandler(Dart_LibraryTag tag,
Dart_Handle library,
Dart_Handle url) {
@@ -292,17 +303,36 @@
const char* mapped_url_string = DartUtils::MapLibraryUrl(url_mapping,
url_string);
+ Builtin::BuiltinLibraryId libraryBuiltinId = BuiltinId(library_url_string);
if (tag == kCanonicalizeUrl) {
- // Keep original names for libraries that have a mapping (e.g. dart:io).
if (mapped_url_string) {
return url;
}
+ // Parts of internal libraries are handled internally.
+ if (libraryBuiltinId != Builtin::kInvalidLibrary) {
+ return url;
+ }
return ResolveUri(library_url_string, url_string);
}
- if (DartUtils::IsDartIOLibURL(url_string) && mapped_url_string == NULL) {
- // No url mapping for dart:io. Load original version.
- return Builtin::LoadAndCheckLibrary(Builtin::kIOLibrary);
+ Builtin::BuiltinLibraryId builtinId = BuiltinId(url_string);
+ if (builtinId != Builtin::kInvalidLibrary) {
+ // Special case for importing a builtin library.
+ if (tag == kImportTag) {
+ return Builtin::LoadAndCheckLibrary(builtinId);
+ }
+ ASSERT(tag == kSourceTag);
+ return Dart_Error("Unable to part '%s' ", url_string);
+ }
+
+ if (libraryBuiltinId != Builtin::kInvalidLibrary) {
+ // Special case for parting sources of a builtin library.
+ if (tag == kSourceTag) {
+ return Dart_LoadSource(
+ library, url, Builtin::PartSource(libraryBuiltinId, url_string));
+ }
+ ASSERT(tag == kImportTag);
+ return Dart_Error("Unable to import '%s' ", url_string);
}
Dart_Handle resolved_url = url;
diff --git a/runtime/bin/socket_patch.dart b/runtime/bin/socket_patch.dart
index d10f3ae..3de4c29 100644
--- a/runtime/bin/socket_patch.dart
+++ b/runtime/bin/socket_patch.dart
@@ -867,13 +867,12 @@
void done([error]) {
if (streamCompleter != null) {
- var tmp = streamCompleter;
- streamCompleter = null;
if (error != null) {
- tmp.completeError(error);
+ streamCompleter.completeError(error);
} else {
- tmp.complete(socket);
+ streamCompleter.complete(socket);
}
+ streamCompleter = null;
}
}
diff --git a/runtime/embedders/openglui/build_skia.sh b/runtime/embedders/openglui/build_skia.sh
index 03f0f5b..42710a8 100755
--- a/runtime/embedders/openglui/build_skia.sh
+++ b/runtime/embedders/openglui/build_skia.sh
@@ -61,7 +61,7 @@
if [ ${DO_ANDROID} != 0 ] ; then
echo "Building for Android ${TARGET_ARCH}"
- curl http://skia.googlecode.com/svn/android/gclient.config -o .gclient
+ curl http://skia.googlecode.com/svn/trunk/platform_tools/android/gclient.config -o .gclient
gclient sync
export ANDROID_SDK_ROOT=`readlink -f ../android_tools/sdk`
@@ -71,9 +71,10 @@
echo "Using SDK ${ANDROID_SDK_ROOT}"
if [ ${CLEAN} != 0 ] ; then
- ../android/bin/android_make -d $TARGET_ARCH -j clean
+ ./platform_tools/android/bin/android_make -d $TARGET_ARCH -j clean
else
- env -i BUILDTYPE=$BUILD ANDROID_SDK_ROOT="${ANDROID_SDK_ROOT}" PATH="${PATH}:${GSUTIL_LOCATION}" ../android/bin/android_make BUILDTYPE=$BUILD -d $TARGET_ARCH -j --debug=j
+ echo env -i BUILDTYPE=$BUILD ANDROID_SDK_ROOT="${ANDROID_SDK_ROOT}" PATH="${PATH}:${GSUTIL_LOCATION}" ../android/bin/android_make BUILDTYPE=$BUILD -d $TARGET_ARCH -j --debug=j
+ env -i BUILDTYPE=$BUILD ANDROID_SDK_ROOT="${ANDROID_SDK_ROOT}" PATH="${PATH}:${GSUTIL_LOCATION}" ./platform_tools/android/bin/android_make BUILDTYPE=$BUILD -d $TARGET_ARCH -j --debug=j
fi
else
diff --git a/runtime/embedders/openglui/openglui_embedder.gypi b/runtime/embedders/openglui/openglui_embedder.gypi
index c3671ee..c67cf90 100644
--- a/runtime/embedders/openglui/openglui_embedder.gypi
+++ b/runtime/embedders/openglui/openglui_embedder.gypi
@@ -50,6 +50,7 @@
'../../vm/version.h',
'../../../third_party/android_tools/ndk/sources/android/native_app_glue/android_native_app_glue.h',
'../../../third_party/android_tools/ndk/sources/android/native_app_glue/android_native_app_glue.c',
+ '../../../third_party/skia/trunk/src/core/SkPaintOptionsAndroid.cpp',
'android/android_graphics_handler.cc',
'android/android_graphics_handler.h',
'android/android_input_handler.h',
@@ -115,6 +116,10 @@
'-lgif',
'-ljpeg',
'-lpng',
+ '-lwebp_dec',
+ '-lwebp_utils',
+ '-lwebp_dsp',
+ '-lwebp_enc',
'-lskia_core',
'-lskia_effects',
'-lskia_gr',
@@ -264,7 +269,8 @@
'-lGL',
'-lglut',
'-lGLU',
- '-lm'
+ '-lm',
+ '-lwebp'
],
},
'conditions': [
diff --git a/runtime/lib/double.cc b/runtime/lib/double.cc
index 2b1f1c7..dbc6886 100644
--- a/runtime/lib/double.cc
+++ b/runtime/lib/double.cc
@@ -80,8 +80,8 @@
Exceptions::ThrowByType(Exceptions::kUnsupported, args);
}
const Bigint& big = Bigint::Handle(BigintOperations::NewFromDouble(val));
- if (BigintOperations::FitsIntoMint(big)) {
- return Integer::New(BigintOperations::ToMint(big));
+ if (BigintOperations::FitsIntoInt64(big)) {
+ return Integer::New(BigintOperations::ToInt64(big));
} else {
return big.raw();
}
diff --git a/runtime/lib/integers.cc b/runtime/lib/integers.cc
index d368415..eb8bd93 100644
--- a/runtime/lib/integers.cc
+++ b/runtime/lib/integers.cc
@@ -24,7 +24,7 @@
if (i.IsBigint()) {
const Bigint& bigint = Bigint::Cast(i);
return !BigintOperations::FitsIntoSmi(bigint) &&
- !BigintOperations::FitsIntoMint(bigint);
+ !BigintOperations::FitsIntoInt64(bigint);
}
if (i.IsMint()) {
const Mint& mint = Mint::Cast(i);
diff --git a/runtime/lib/math_patch.dart b/runtime/lib/math_patch.dart
index a0c7711..c279c19 100644
--- a/runtime/lib/math_patch.dart
+++ b/runtime/lib/math_patch.dart
@@ -68,27 +68,31 @@
// The algorithm used here is Multiply with Carry (MWC) with a Base b = 2^32.
// http://en.wikipedia.org/wiki/Multiply-with-carry
// The constant A is selected from "Numerical Recipes 3rd Edition" p.348 B1.
- int _nextInt32() {
+ void _nextState() {
var state = ((_A * (_state[kSTATE_LO])) + _state[kSTATE_HI]) & _MASK_64;
_state[kSTATE_LO] = state & _MASK_32;
_state[kSTATE_HI] = state >> 32;
- return _state[kSTATE_LO];
}
int nextInt(int max) {
- if (max <= 0 || max > _POW2_32) {
+ // TODO(srdjan): Remove the 'limit' check once optimizing comparison of
+ // Smi-s with Mint constants.
+ final limit = 0x3FFFFFFF;
+ if (max <= 0 || ((max > limit) && (max > _POW2_32))) {
throw new ArgumentError("max must be positive and < 2^32:"
" $max");
}
if ((max & -max) == max) {
// Fast case for powers of two.
- return _nextInt32() & (max - 1);
+ _nextState();
+ return _state[kSTATE_LO] & (max - 1);
}
var rnd32;
var result;
do {
- rnd32 = _nextInt32();
+ _nextState();
+ rnd32 = _state[kSTATE_LO];
result = rnd32 % max;
} while ((rnd32 - result + max) >= _POW2_32);
return result;
@@ -119,6 +123,7 @@
_prng = new Random(new DateTime.now().millisecondsSinceEpoch);
}
// Trigger the PRNG once to change the internal state.
- return _prng._nextInt32();
+ _prng._nextState();
+ return _prng._state[kSTATE_LO];
}
}
diff --git a/runtime/lib/object.cc b/runtime/lib/object.cc
index ac26d087..a4a3faf 100644
--- a/runtime/lib/object.cc
+++ b/runtime/lib/object.cc
@@ -17,8 +17,7 @@
DEFINE_NATIVE_ENTRY(Object_cid, 1) {
const Instance& instance = Instance::CheckedHandle(arguments->NativeArgAt(0));
- const Class& cls = Class::Handle(instance.clazz());
- return Smi::New(cls.id());
+ return Smi::New(instance.GetClassId());
}
diff --git a/runtime/lib/string_patch.dart b/runtime/lib/string_patch.dart
index e9f5759..dbe8dc0 100644
--- a/runtime/lib/string_patch.dart
+++ b/runtime/lib/string_patch.dart
@@ -199,6 +199,43 @@
String _substringUncheckedNative(int startIndex, int endIndex)
native "StringBase_substringUnchecked";
+ // Checks for one-byte whitespaces only.
+ static bool _isOneByteWhitespace(int codePoint) {
+ return
+ (codePoint == 32) || // Space.
+ ((9 <= codePoint) && (codePoint <= 13)) || // CR, LF, TAB, etc.
+ (codePoint == 0x85) || // NEL
+ (codePoint == 0xA0); // NBSP
+ }
+
+ // Characters with Whitespace property (Unicode 6.2).
+ // 0009..000D ; White_Space # Cc <control-0009>..<control-000D>
+ // 0020 ; White_Space # Zs SPACE
+ // 0085 ; White_Space # Cc <control-0085>
+ // 00A0 ; White_Space # Zs NO-BREAK SPACE
+ // 1680 ; White_Space # Zs OGHAM SPACE MARK
+ // 180E ; White_Space # Zs MONGOLIAN VOWEL SEPARATOR
+ // 2000..200A ; White_Space # Zs EN QUAD..HAIR SPACE
+ // 2028 ; White_Space # Zl LINE SEPARATOR
+ // 2029 ; White_Space # Zp PARAGRAPH SEPARATOR
+ // 202F ; White_Space # Zs NARROW NO-BREAK SPACE
+ // 205F ; White_Space # Zs MEDIUM MATHEMATICAL SPACE
+ // 3000 ; White_Space # Zs IDEOGRAPHIC SPACE
+ //
+ // BOM: 0xFEFF
+ static bool _isTwoByteWhitespace(int codePoint) {
+ if (codePoint < 256) return _isOneByteWhitespace(codePoint);
+ return (codePoint == 0x1680) ||
+ (codePoint == 0x180E) ||
+ ((0x2000 <= codePoint) && (codePoint <= 0x200A)) ||
+ (codePoint == 0x2028) ||
+ (codePoint == 0x2029) ||
+ (codePoint == 0x202F) ||
+ (codePoint == 0x205F) ||
+ (codePoint == 0x3000) ||
+ (codePoint == 0xFEFF);
+ }
+
String trim() {
final int len = this.length;
int first = 0;
@@ -510,13 +547,8 @@
int get hashCode native "String_getHashCode";
- // Checks for one-byte whitespaces only.
- // TODO(srdjan): Investigate if 0x85 (NEL) and 0xA0 (NBSP) are valid
- // whitespaces for one byte strings.
bool _isWhitespace(int codePoint) {
- return
- (codePoint == 32) || // Space.
- ((9 <= codePoint) && (codePoint <= 13)); // CR, LF, TAB, etc.
+ return _StringBase._isOneByteWhitespace(codePoint);
}
String _substringUncheckedNative(int startIndex, int endIndex)
@@ -568,30 +600,8 @@
"_TwoByteString can only be allocated by the VM");
}
- // Checks for one-byte whitespaces only.
- // TODO(srdjan): Investigate if 0x85 (NEL) and 0xA0 (NBSP) are valid
- // whitespaces. Add checking for multi-byte whitespace codepoints.
bool _isWhitespace(int codePoint) {
- return
- (codePoint == 32) || // Space.
- ((9 <= codePoint) && (codePoint <= 13)); // CR, LF, TAB, etc.
- }
-}
-
-
-class _FourByteString extends _StringBase implements String {
- factory _FourByteString._uninstantiable() {
- throw new UnsupportedError(
- "_FourByteString can only be allocated by the VM");
- }
-
- // Checks for one-byte whitespaces only.
- // TODO(srdjan): Investigate if 0x85 (NEL) and 0xA0 (NBSP) are valid
- // whitespaces. Add checking for multi-byte whitespace codepoints.
- bool _isWhitespace(int codePoint) {
- return
- (codePoint == 32) || // Space.
- ((9 <= codePoint) && (codePoint <= 13)); // CR, LF, TAB, etc.
+ return _StringBase._isTwoByteWhitespace(codePoint);
}
}
@@ -602,13 +612,8 @@
"_ExternalOneByteString can only be allocated by the VM");
}
- // Checks for one-byte whitespaces only.
- // TODO(srdjan): Investigate if 0x85 (NEL) and 0xA0 (NBSP) are valid
- // whitespaces for one byte strings.
bool _isWhitespace(int codePoint) {
- return
- (codePoint == 32) || // Space.
- ((9 <= codePoint) && (codePoint <= 13)); // CR, LF, TAB, etc.
+ return _StringBase._isOneByteWhitespace(codePoint);
}
}
@@ -619,13 +624,8 @@
"_ExternalTwoByteString can only be allocated by the VM");
}
- // Checks for one-byte whitespaces only.
- // TODO(srdjan): Investigate if 0x85 (NEL) and 0xA0 (NBSP) are valid
- // whitespaces. Add checking for multi-byte whitespace codepoints.
bool _isWhitespace(int codePoint) {
- return
- (codePoint == 32) || // Space.
- ((9 <= codePoint) && (codePoint <= 13)); // CR, LF, TAB, etc.
+ return _StringBase._isTwoByteWhitespace(codePoint);
}
}
diff --git a/runtime/tests/vm/vm.status b/runtime/tests/vm/vm.status
index 5787071..a79042d 100644
--- a/runtime/tests/vm/vm.status
+++ b/runtime/tests/vm/vm.status
@@ -81,3 +81,8 @@
cc/CustomIsolates: Skip # Bug 6890
cc/NewNativePort: Skip # Bug 6890
cc/RunLoop_ExceptionParent: Skip # Bug 6890
+
+[ $compiler == dartanalyzer ]
+# has compilation error, as designed
+dart/isolate_mirror_local_test: fail
+
diff --git a/runtime/vm/bigint_operations.cc b/runtime/vm/bigint_operations.cc
index 118a836..709baa2 100644
--- a/runtime/vm/bigint_operations.cc
+++ b/runtime/vm/bigint_operations.cc
@@ -605,7 +605,7 @@
}
-bool BigintOperations::FitsIntoMint(const Bigint& bigint) {
+bool BigintOperations::FitsIntoInt64(const Bigint& bigint) {
intptr_t bigint_length = bigint.Length();
if (bigint_length == 0) {
return true;
@@ -663,11 +663,11 @@
}
-int64_t BigintOperations::ToMint(const Bigint& bigint) {
+int64_t BigintOperations::ToInt64(const Bigint& bigint) {
if (bigint.IsZero()) {
return 0;
}
- ASSERT(FitsIntoMint(bigint));
+ ASSERT(FitsIntoInt64(bigint));
int64_t value = AbsToUint64(bigint);
if (bigint.IsNegative()) {
value = -value;
diff --git a/runtime/vm/bigint_operations.h b/runtime/vm/bigint_operations.h
index e9c31a2..892ee6c 100644
--- a/runtime/vm/bigint_operations.h
+++ b/runtime/vm/bigint_operations.h
@@ -62,8 +62,8 @@
static bool FitsIntoSmi(const Bigint& bigint);
static RawSmi* ToSmi(const Bigint& bigint);
- static bool FitsIntoMint(const Bigint& bigint);
- static int64_t ToMint(const Bigint& bigint);
+ static bool FitsIntoInt64(const Bigint& bigint);
+ static int64_t ToInt64(const Bigint& bigint);
static bool FitsIntoUint64(const Bigint& bigint);
static bool AbsFitsIntoUint64(const Bigint& bigint);
diff --git a/runtime/vm/bigint_operations_test.cc b/runtime/vm/bigint_operations_test.cc
index 0c141a1..b43ff90 100644
--- a/runtime/vm/bigint_operations_test.cc
+++ b/runtime/vm/bigint_operations_test.cc
@@ -79,45 +79,45 @@
const Bigint& one = Bigint::Handle(BigintOperations::NewFromInt64(1));
big = BigintOperations::NewFromInt64(kMinInt64);
- EXPECT(BigintOperations::FitsIntoMint(big));
- int64_t back = BigintOperations::ToMint(big);
+ EXPECT(BigintOperations::FitsIntoInt64(big));
+ int64_t back = BigintOperations::ToInt64(big);
EXPECT_EQ(kMinInt64, back);
big = BigintOperations::Subtract(big, one);
- EXPECT(!BigintOperations::FitsIntoMint(big));
+ EXPECT(!BigintOperations::FitsIntoInt64(big));
big = BigintOperations::NewFromInt64(kMaxInt64);
- EXPECT(BigintOperations::FitsIntoMint(big));
- back = BigintOperations::ToMint(big);
+ EXPECT(BigintOperations::FitsIntoInt64(big));
+ back = BigintOperations::ToInt64(big);
EXPECT_EQ(kMaxInt64, back);
big = BigintOperations::Add(big, one);
- EXPECT(!BigintOperations::FitsIntoMint(big));
+ EXPECT(!BigintOperations::FitsIntoInt64(big));
}
TEST_CASE(BigintUint64) {
const Bigint& one = Bigint::Handle(BigintOperations::NewFromUint64(1));
- EXPECT(BigintOperations::FitsIntoMint(one));
+ EXPECT(BigintOperations::FitsIntoInt64(one));
EXPECT(BigintOperations::FitsIntoUint64(one));
Bigint& big = Bigint::Handle(BigintOperations::NewFromUint64(kMaxUint64));
- EXPECT(!BigintOperations::FitsIntoMint(big));
+ EXPECT(!BigintOperations::FitsIntoInt64(big));
EXPECT(BigintOperations::FitsIntoUint64(big));
uint64_t back = BigintOperations::ToUint64(big);
EXPECT_EQ(kMaxUint64, back);
big = BigintOperations::Add(big, one);
- EXPECT(!BigintOperations::FitsIntoMint(big));
+ EXPECT(!BigintOperations::FitsIntoInt64(big));
EXPECT(!BigintOperations::FitsIntoUint64(big));
big = BigintOperations::Subtract(big, one);
- EXPECT(!BigintOperations::FitsIntoMint(big));
+ EXPECT(!BigintOperations::FitsIntoInt64(big));
EXPECT(BigintOperations::FitsIntoUint64(big));
big = BigintOperations::ShiftRight(big, 1);
- EXPECT(BigintOperations::FitsIntoMint(big));
+ EXPECT(BigintOperations::FitsIntoInt64(big));
EXPECT(BigintOperations::FitsIntoUint64(big));
}
diff --git a/runtime/vm/class_finalizer.cc b/runtime/vm/class_finalizer.cc
index 673df7a..aa843a5 100644
--- a/runtime/vm/class_finalizer.cc
+++ b/runtime/vm/class_finalizer.cc
@@ -115,7 +115,7 @@
ASSERT(isolate != NULL);
HANDLESCOPE(isolate);
ObjectStore* object_store = isolate->object_store();
- const Error& error = Error::Handle(object_store->sticky_error());
+ const Error& error = Error::Handle(isolate, object_store->sticky_error());
if (!error.IsNull()) {
return false;
}
diff --git a/runtime/vm/code_generator.cc b/runtime/vm/code_generator.cc
index 8d74e7b..fb7a9e8 100644
--- a/runtime/vm/code_generator.cc
+++ b/runtime/vm/code_generator.cc
@@ -893,13 +893,12 @@
Function::Handle(target_code.function());
ASSERT(!target_function.IsNull());
if (args.length() == 1) {
- ic_data.AddReceiverCheck(Class::Handle(args[0]->clazz()).id(),
- target_function);
+ ic_data.AddReceiverCheck(args[0]->GetClassId(), target_function);
} else {
GrowableArray<intptr_t> class_ids(args.length());
ASSERT(ic_data.num_args_tested() == args.length());
for (intptr_t i = 0; i < args.length(); i++) {
- class_ids.Add(Class::Handle(args[i]->clazz()).id());
+ class_ids.Add(args[i]->GetClassId());
}
ic_data.AddCheck(class_ids, target_function);
}
@@ -921,7 +920,7 @@
args.length(),
caller_frame->pc(),
Class::Handle(receiver.clazz()).ToCString(),
- Class::Handle(receiver.clazz()).id(),
+ receiver.GetClassId(),
target_function.ToCString());
}
}
@@ -1088,8 +1087,8 @@
ASSERT(!target_function.IsNull());
GrowableArray<intptr_t> class_ids(kNumArguments);
ASSERT(ic_data.num_args_tested() == kNumArguments);
- class_ids.Add(Class::Handle(receiver.clazz()).id());
- class_ids.Add(Class::Handle(arg1.clazz()).id());
+ class_ids.Add(receiver.GetClassId());
+ class_ids.Add(arg1.GetClassId());
ic_data.AddCheck(class_ids, target_function);
}
@@ -1771,7 +1770,7 @@
const Field& field = Field::CheckedHandle(arguments.ArgAt(0));
const Object& value = Object::Handle(arguments.ArgAt(1));
- field.UpdateCid(Class::Handle(value.clazz()).id());
+ field.UpdateCid(value.GetClassId());
}
} // namespace dart
diff --git a/runtime/vm/compiler.cc b/runtime/vm/compiler.cc
index 696dbb2..764dfbc 100644
--- a/runtime/vm/compiler.cc
+++ b/runtime/vm/compiler.cc
@@ -121,7 +121,6 @@
bool is_compiled = false;
Isolate* isolate = Isolate::Current();
HANDLESCOPE(isolate);
- ASSERT(isolate->ic_data_array() == Array::null()); // Must be reset to null.
const intptr_t prev_deopt_id = isolate->deopt_id();
isolate->set_deopt_id(0);
LongJump* old_base = isolate->long_jump_base();
@@ -135,6 +134,7 @@
TimerScope timer(FLAG_compiler_stats,
&CompilerStats::graphbuilder_timer,
isolate);
+ Array& ic_data_array = Array::Handle();
if (optimized) {
ASSERT(parsed_function.function().HasCode());
// Extract type feedback before the graph is built, as the graph
@@ -145,13 +145,14 @@
FLAG_deoptimization_counter_threshold) {
const Code& unoptimized_code =
Code::Handle(parsed_function.function().unoptimized_code());
- isolate->set_ic_data_array(
- unoptimized_code.ExtractTypeFeedbackArray());
+ ic_data_array = unoptimized_code.ExtractTypeFeedbackArray();
}
}
// Build the flow graph.
- FlowGraphBuilder builder(parsed_function, NULL); // NULL = not inlining.
+ FlowGraphBuilder builder(parsed_function,
+ ic_data_array,
+ NULL); // NULL = not inlining.
flow_graph = builder.BuildGraph();
}
@@ -396,7 +397,6 @@
is_compiled = false;
}
// Reset global isolate state.
- isolate->set_ic_data_array(Array::null());
isolate->set_long_jump_base(old_base);
isolate->set_deopt_id(prev_deopt_id);
return is_compiled;
diff --git a/runtime/vm/dart_api_impl.cc b/runtime/vm/dart_api_impl.cc
index aa6738a..0707a20 100644
--- a/runtime/vm/dart_api_impl.cc
+++ b/runtime/vm/dart_api_impl.cc
@@ -1326,7 +1326,7 @@
if (int_obj.IsNull()) {
RETURN_TYPE_ERROR(isolate, integer, Integer);
}
- ASSERT(!BigintOperations::FitsIntoMint(Bigint::Cast(int_obj)));
+ ASSERT(!BigintOperations::FitsIntoInt64(Bigint::Cast(int_obj)));
*fits = false;
return Api::Success(isolate);
}
@@ -1402,8 +1402,8 @@
return Api::Success(isolate);
} else {
const Bigint& bigint = Bigint::Cast(int_obj);
- if (BigintOperations::FitsIntoMint(bigint)) {
- *value = BigintOperations::ToMint(bigint);
+ if (BigintOperations::FitsIntoInt64(bigint)) {
+ *value = BigintOperations::ToInt64(bigint);
return Api::Success(isolate);
}
}
@@ -1949,7 +1949,7 @@
// Check for a non-canonical Mint range value.
ASSERT(retval.IsBigint());
const Bigint& bigint = Bigint::Handle();
- if (BigintOperations::FitsIntoMint(bigint)) {
+ if (BigintOperations::FitsIntoInt64(bigint)) {
int64_t bigint_value = bigint.AsInt64Value();
if (bigint_value >= kIntptrMin && bigint_value <= kIntptrMax) {
*len = static_cast<intptr_t>(bigint_value);
@@ -3934,10 +3934,14 @@
RETURN_TYPE_ERROR(isolate, name, String);
}
- const Object& obj = Object::Handle(isolate, Api::UnwrapHandle(container));
-
+ // Finalize all classes.
+ Dart_Handle state = Api::CheckIsolateState(isolate);
+ if (::Dart_IsError(state)) {
+ return state;
+ }
Field& field = Field::Handle(isolate);
Function& getter = Function::Handle(isolate);
+ const Object& obj = Object::Handle(isolate, Api::UnwrapHandle(container));
if (obj.IsNull()) {
return Api::NewError("%s expects argument 'container' to be non-null.",
CURRENT_FUNC);
@@ -3973,11 +3977,6 @@
return Api::NewHandle(isolate, DartEntry::InvokeFunction(getter, args));
} else if (obj.IsClass()) {
- // Finalize all classes.
- Dart_Handle state = Api::CheckIsolateState(isolate);
- if (::Dart_IsError(state)) {
- return state;
- }
// To access a static field we may need to use the Field or the
// getter Function.
const Class& cls = Class::Cast(obj);
@@ -4000,8 +3999,6 @@
}
} else if (obj.IsLibrary()) {
- // TODO(turnidge): Do we need to call CheckIsolateState here?
-
// To access a top-level we may need to use the Field or the
// getter Function. The getter function may either be in the
// library or in the field's owner class, depending.
@@ -4061,6 +4058,11 @@
Instance& value_instance = Instance::Handle(isolate);
value_instance ^= value_obj.raw();
+ // Finalize all classes.
+ Dart_Handle state = Api::CheckIsolateState(isolate);
+ if (::Dart_IsError(state)) {
+ return state;
+ }
Field& field = Field::Handle(isolate);
Function& setter = Function::Handle(isolate);
const Object& obj = Object::Handle(isolate, Api::UnwrapHandle(container));
diff --git a/runtime/vm/dart_api_impl_test.cc b/runtime/vm/dart_api_impl_test.cc
index 047df63..6d8626a 100644
--- a/runtime/vm/dart_api_impl_test.cc
+++ b/runtime/vm/dart_api_impl_test.cc
@@ -3516,6 +3516,53 @@
}
+TEST_CASE(GetField_CheckIsolate) {
+ const char* kScriptChars =
+ "class TestClass {\n"
+ " static int fld2 = 11;\n"
+ " static void testMain() {\n"
+ " }\n"
+ "}\n";
+ Dart_Handle result;
+ int64_t value = 0;
+
+ // Create a test library and Load up a test script in it.
+ Dart_Handle lib = TestCase::LoadTestScript(kScriptChars, NULL);
+ Dart_Handle cls = Dart_GetClass(lib, NewString("TestClass"));
+ EXPECT_VALID(cls);
+
+ result = Dart_GetField(cls, NewString("fld2"));
+ EXPECT_VALID(result);
+ result = Dart_IntegerToInt64(result, &value);
+ EXPECT_EQ(11, value);
+}
+
+
+TEST_CASE(SetField_CheckIsolate) {
+ const char* kScriptChars =
+ "class TestClass {\n"
+ " static int fld2 = 11;\n"
+ " static void testMain() {\n"
+ " }\n"
+ "}\n";
+ Dart_Handle result;
+ int64_t value = 0;
+
+ // Create a test library and Load up a test script in it.
+ Dart_Handle lib = TestCase::LoadTestScript(kScriptChars, NULL);
+ Dart_Handle cls = Dart_GetClass(lib, NewString("TestClass"));
+ EXPECT_VALID(cls);
+
+ result = Dart_SetField(cls, NewString("fld2"), Dart_NewInteger(13));
+ EXPECT_VALID(result);
+
+ result = Dart_GetField(cls, NewString("fld2"));
+ EXPECT_VALID(result);
+ result = Dart_IntegerToInt64(result, &value);
+ EXPECT_EQ(13, value);
+}
+
+
TEST_CASE(New) {
const char* kScriptChars =
"class MyClass {\n"
diff --git a/runtime/vm/dart_entry.cc b/runtime/vm/dart_entry.cc
index 1b9e361..89ebb10 100644
--- a/runtime/vm/dart_entry.cc
+++ b/runtime/vm/dart_entry.cc
@@ -176,17 +176,17 @@
intptr_t ArgumentsDescriptor::count_offset() {
- return Array::data_offset() + (kCountIndex * kWordSize);
+ return Array::element_offset(kCountIndex);
}
intptr_t ArgumentsDescriptor::positional_count_offset() {
- return Array::data_offset() + (kPositionalCountIndex * kWordSize);
+ return Array::element_offset(kPositionalCountIndex);
}
intptr_t ArgumentsDescriptor::first_named_entry_offset() {
- return Array::data_offset() + (kFirstNamedEntryIndex * kWordSize);
+ return Array::element_offset(kFirstNamedEntryIndex);
}
diff --git a/runtime/vm/debugger.cc b/runtime/vm/debugger.cc
index a470b0a..0d80af0 100644
--- a/runtime/vm/debugger.cc
+++ b/runtime/vm/debugger.cc
@@ -779,7 +779,6 @@
src_breakpoints_(NULL),
code_breakpoints_(NULL),
resume_action_(kContinue),
- last_bpt_line_(-1),
ignore_breakpoints_(false),
exc_pause_info_(kNoPauseOnExceptions) {
}
@@ -1024,8 +1023,6 @@
if (!ShouldPauseOnException(stack_trace, exc)) {
return;
}
- // No single-stepping possible after this pause event.
- last_bpt_line_ = -1;
ASSERT(stack_trace_ == NULL);
stack_trace_ = stack_trace;
ASSERT(obj_cache_ == NULL);
@@ -1532,31 +1529,19 @@
top_frame->pc());
}
- if (!bpt->IsInternal()) {
- // This is a user-defined breakpoint so we call the breakpoint
- // callback even if it is on the same line as the previous breakpoint.
- last_bpt_line_ = -1;
- }
-
- bool notify_frontend =
- (last_bpt_line_ < 0) || (last_bpt_line_ != bpt->LineNumber());
-
- if (notify_frontend) {
- resume_action_ = kContinue;
- if (event_handler_ != NULL) {
- ASSERT(stack_trace_ == NULL);
- ASSERT(obj_cache_ == NULL);
- obj_cache_ = new RemoteObjectCache(64);
- stack_trace_ = stack_trace;
- DebuggerEvent event;
- event.type = kBreakpointReached;
- ASSERT(stack_trace->Length() > 0);
- event.top_frame = stack_trace->ActivationFrameAt(0);
- (*event_handler_)(&event);
- stack_trace_ = NULL;
- obj_cache_ = NULL; // Remote object cache is zone allocated.
- last_bpt_line_ = bpt->LineNumber();
- }
+ resume_action_ = kContinue;
+ if (event_handler_ != NULL) {
+ ASSERT(stack_trace_ == NULL);
+ ASSERT(obj_cache_ == NULL);
+ obj_cache_ = new RemoteObjectCache(64);
+ stack_trace_ = stack_trace;
+ DebuggerEvent event;
+ event.type = kBreakpointReached;
+ ASSERT(stack_trace->Length() > 0);
+ event.top_frame = stack_trace->ActivationFrameAt(0);
+ (*event_handler_)(&event);
+ stack_trace_ = NULL;
+ obj_cache_ = NULL; // Remote object cache is zone allocated.
}
Function& currently_instrumented_func = Function::Handle();
@@ -1656,7 +1641,6 @@
if (func_to_instrument.IsNull() ||
(func_to_instrument.raw() != currently_instrumented_func.raw())) {
- last_bpt_line_ = -1;
RemoveInternalBreakpoints(); // *bpt is now invalid.
if (!func_to_instrument.IsNull()) {
InstrumentForStepping(func_to_instrument);
diff --git a/runtime/vm/debugger.h b/runtime/vm/debugger.h
index d184d3b..9df08bd 100644
--- a/runtime/vm/debugger.h
+++ b/runtime/vm/debugger.h
@@ -373,10 +373,6 @@
// Tells debugger what to do when resuming execution after a breakpoint.
ResumeAction resume_action_;
- // If >= 0, last_bpt_line contains the line number of the last breakpoint
- // location for which the breakpoint callback function was called.
- intptr_t last_bpt_line_;
-
// Do not call back to breakpoint handler if this flag is set.
// Effectively this means ignoring breakpoints. Set when Dart code may
// be run as a side effect of getting values of fields.
diff --git a/runtime/vm/debugger_api_impl.cc b/runtime/vm/debugger_api_impl.cc
index 43a80d4..123db7c 100644
--- a/runtime/vm/debugger_api_impl.cc
+++ b/runtime/vm/debugger_api_impl.cc
@@ -492,7 +492,7 @@
DARTSCOPE(isolate);
UNWRAP_AND_CHECK_PARAM(Instance, obj, object_in);
CHECK_NOT_NULL(class_id);
- *class_id = Class::Handle(obj.clazz()).id();
+ *class_id = obj.GetClassId();
return Api::True(isolate);
}
diff --git a/runtime/vm/debugger_api_impl_test.cc b/runtime/vm/debugger_api_impl_test.cc
index a10bbeb..6810a61b 100644
--- a/runtime/vm/debugger_api_impl_test.cc
+++ b/runtime/vm/debugger_api_impl_test.cc
@@ -361,10 +361,12 @@
"f1",
"foo",
"X.X.",
+ "X.X.",
"foo",
"X.kvmk",
"f2",
"X.kvmk",
+ "X.kvmk",
"foo",
"main"
};
@@ -418,11 +420,7 @@
LoadScript(kScriptChars);
Dart_SetPausedEventHandler(&TestStepIntoHandler);
- // Set a breakpoint in function f1, then repeatedly step out until
- // we get to main. We should see one breakpoint each in f1,
- // foo, main, but not in f2.
SetBreakpointAtEntry("", "main");
-
breakpoint_hit = false;
breakpoint_hit_counter = 0;
Dart_Handle retval = Invoke("main");
diff --git a/runtime/vm/flow_graph_builder.cc b/runtime/vm/flow_graph_builder.cc
index bd43c7a..d27f76c 100644
--- a/runtime/vm/flow_graph_builder.cc
+++ b/runtime/vm/flow_graph_builder.cc
@@ -42,8 +42,10 @@
FlowGraphBuilder::FlowGraphBuilder(const ParsedFunction& parsed_function,
+ const Array& ic_data_array,
InlineExitCollector* exit_collector)
: parsed_function_(parsed_function),
+ ic_data_array_(ic_data_array),
num_copied_params_(parsed_function.num_copied_params()),
// All parameters are copied if any parameter is.
num_non_copied_params_((num_copied_params_ == 0)
@@ -926,7 +928,8 @@
node->kind(),
arguments,
Array::ZoneHandle(),
- 2);
+ 2,
+ owner()->ic_data_array());
ReturnDefinition(call);
}
@@ -1168,7 +1171,8 @@
node->kind(),
arguments,
Array::ZoneHandle(), // No argument names.
- kNumArgsChecked);
+ kNumArgsChecked,
+ owner()->ic_data_array());
ReturnDefinition(call);
}
@@ -1237,7 +1241,8 @@
node->kind(),
arguments,
Array::ZoneHandle(), // No argument names.
- kNumArgsChecked);
+ kNumArgsChecked,
+ owner()->ic_data_array());
ReturnDefinition(call);
}
}
@@ -1282,7 +1287,8 @@
node->token_pos(),
Token::kEQ,
for_left_value.value(),
- for_right_value.value());
+ for_right_value.value(),
+ owner()->ic_data_array());
if (node->kind() == Token::kEQ) {
ReturnDefinition(comp);
} else {
@@ -1295,7 +1301,8 @@
node->token_pos(),
node->kind(),
for_left_value.value(),
- for_right_value.value());
+ for_right_value.value(),
+ owner()->ic_data_array());
ReturnDefinition(comp);
}
return;
@@ -1310,7 +1317,8 @@
RelationalOpInstr* comp = new RelationalOpInstr(node->token_pos(),
node->kind(),
for_left_value.value(),
- for_right_value.value());
+ for_right_value.value(),
+ owner()->ic_data_array());
ReturnDefinition(comp);
}
@@ -1345,7 +1353,8 @@
node->kind(),
arguments,
Array::ZoneHandle(),
- 1);
+ 1,
+ owner()->ic_data_array());
ReturnDefinition(call);
}
@@ -1913,7 +1922,9 @@
InstanceCallInstr* call = new InstanceCallInstr(
node->token_pos(),
node->function_name(), Token::kILLEGAL, arguments,
- node->arguments()->names(), 1);
+ node->arguments()->names(),
+ 1,
+ owner()->ic_data_array());
ReturnDefinition(call);
}
@@ -2017,32 +2028,37 @@
// In checked mode, if the type arguments are uninstantiated, they may need to
// be checked against declared bounds at run time.
- Definition* allocate_comp = NULL;
+ Definition* allocation = NULL;
if (FLAG_enable_type_checks &&
requires_type_arguments &&
!node->type_arguments().IsNull() &&
!node->type_arguments().IsInstantiated() &&
node->type_arguments().IsBounded()) {
- Value* type_arguments = NULL;
- Value* instantiator = NULL;
- BuildConstructorTypeArguments(node, &type_arguments, &instantiator, NULL);
+ ZoneGrowableArray<PushArgumentInstr*>* allocate_arguments =
+ new ZoneGrowableArray<PushArgumentInstr*>(4);
+ // Argument 1: Empty argument slot for return value.
+ Value* null_val = Bind(new ConstantInstr(Object::ZoneHandle()));
+ allocate_arguments->Add(PushArgument(null_val));
+ // Argument 2: Class.
+ Value* cls_val =
+ Bind(new ConstantInstr(Class::ZoneHandle(node->constructor().Owner())));
+ allocate_arguments->Add(PushArgument(cls_val));
+ // Build arguments 3 and 4.
+ BuildConstructorTypeArguments(node, allocate_arguments);
// The uninstantiated type arguments cannot be verified to be within their
// bounds at compile time, so verify them at runtime.
- allocate_comp = new AllocateObjectWithBoundsCheckInstr(node,
- type_arguments,
- instantiator);
+ allocation = new AllocateObjectWithBoundsCheckInstr(node);
} else {
ZoneGrowableArray<PushArgumentInstr*>* allocate_arguments =
new ZoneGrowableArray<PushArgumentInstr*>();
-
if (requires_type_arguments) {
- BuildConstructorTypeArguments(node, NULL, NULL, allocate_arguments);
+ BuildConstructorTypeArguments(node, allocate_arguments);
}
- allocate_comp = new AllocateObjectInstr(node, allocate_arguments);
+ allocation = new AllocateObjectInstr(node, allocate_arguments);
}
- return Bind(allocate_comp);
+ return Bind(allocation);
}
@@ -2249,73 +2265,69 @@
void EffectGraphVisitor::BuildConstructorTypeArguments(
ConstructorCallNode* node,
- Value** type_arguments,
- Value** instantiator,
ZoneGrowableArray<PushArgumentInstr*>* call_arguments) {
const Class& cls = Class::ZoneHandle(node->constructor().Owner());
ASSERT(cls.HasTypeArguments() && !node->constructor().IsFactory());
if (node->type_arguments().IsNull() ||
node->type_arguments().IsInstantiated()) {
Value* type_arguments_val = Bind(new ConstantInstr(node->type_arguments()));
- if (call_arguments != NULL) {
- ASSERT(type_arguments == NULL);
- call_arguments->Add(PushArgument(type_arguments_val));
- } else {
- ASSERT(type_arguments != NULL);
- *type_arguments = type_arguments_val;
- }
+ call_arguments->Add(PushArgument(type_arguments_val));
// No instantiator required.
Value* instantiator_val = Bind(new ConstantInstr(
Smi::ZoneHandle(Smi::New(StubCode::kNoInstantiator))));
- if (call_arguments != NULL) {
- ASSERT(instantiator == NULL);
- call_arguments->Add(PushArgument(instantiator_val));
- } else {
- ASSERT(instantiator != NULL);
- *instantiator = instantiator_val;
- }
+ call_arguments->Add(PushArgument(instantiator_val));
return;
}
+
// The type arguments are uninstantiated. We use expression_temp_var to save
- // the instantiator type arguments becuase they have two uses.
+ // the instantiator type arguments because they have two uses.
ASSERT(owner()->parsed_function().expression_temp_var() != NULL);
const LocalVariable& temp = *owner()->parsed_function().expression_temp_var();
const Class& instantiator_class = Class::Handle(
owner()->parsed_function().function().Owner());
- Value* instantiator_type_arguments = BuildInstantiatorTypeArguments(
+ Value* type_arguments_val = BuildInstantiatorTypeArguments(
node->token_pos(), instantiator_class, NULL);
- Value* stored_instantiator =
- Bind(BuildStoreTemp(temp, instantiator_type_arguments));
- Value* type_arguments_val = Bind(
- new ExtractConstructorTypeArgumentsInstr(
- node->token_pos(),
- node->type_arguments(),
- instantiator_class,
- stored_instantiator));
+ const bool use_instantiator_type_args =
+ node->type_arguments().IsUninstantiatedIdentity() ||
+ node->type_arguments().CanShareInstantiatorTypeArguments(
+ instantiator_class);
- if (call_arguments != NULL) {
- ASSERT(type_arguments == NULL);
- call_arguments->Add(PushArgument(type_arguments_val));
- } else {
- ASSERT(type_arguments != NULL);
- *type_arguments = type_arguments_val;
+ if (!use_instantiator_type_args) {
+ const intptr_t len = node->type_arguments().Length();
+ if (node->type_arguments().IsRawInstantiatedRaw(len)) {
+ type_arguments_val =
+ Bind(BuildStoreTemp(temp, type_arguments_val));
+ type_arguments_val = Bind(
+ new ExtractConstructorTypeArgumentsInstr(
+ node->token_pos(),
+ node->type_arguments(),
+ instantiator_class,
+ type_arguments_val));
+ } else {
+ Do(BuildStoreTemp(temp, type_arguments_val));
+ type_arguments_val = Bind(new ConstantInstr(node->type_arguments()));
+ }
}
+ call_arguments->Add(PushArgument(type_arguments_val));
- Value* load_instantiator = Bind(BuildLoadLocal(temp));
- Value* instantiator_val =
- Bind(new ExtractConstructorInstantiatorInstr(node,
- instantiator_class,
- load_instantiator));
-
- if (call_arguments != NULL) {
- ASSERT(instantiator == NULL);
- call_arguments->Add(PushArgument(instantiator_val));
+ Value* instantiator_val = NULL;
+ if (!use_instantiator_type_args) {
+ instantiator_val = Bind(BuildLoadLocal(temp));
+ const intptr_t len = node->type_arguments().Length();
+ if (node->type_arguments().IsRawInstantiatedRaw(len)) {
+ instantiator_val =
+ Bind(new ExtractConstructorInstantiatorInstr(node,
+ instantiator_class,
+ instantiator_val));
+ }
} else {
- ASSERT(instantiator != NULL);
- *instantiator = instantiator_val;
+ // No instantiator required.
+ instantiator_val = Bind(new ConstantInstr(
+ Smi::ZoneHandle(Smi::New(StubCode::kNoInstantiator))));
}
+ call_arguments->Add(PushArgument(instantiator_val));
}
@@ -2357,8 +2369,12 @@
const String& name =
String::ZoneHandle(Field::GetterSymbol(node->field_name()));
InstanceCallInstr* call = new InstanceCallInstr(
- node->token_pos(), name, Token::kGET,
- arguments, Array::ZoneHandle(), 1);
+ node->token_pos(),
+ name,
+ Token::kGET,
+ arguments, Array::ZoneHandle(),
+ 1,
+ owner()->ic_data_array());
ReturnDefinition(call);
}
@@ -2397,7 +2413,8 @@
Token::kSET,
arguments,
Array::ZoneHandle(),
- 2); // Checked arg count.
+ 2, // Checked arg count.
+ owner()->ic_data_array());
ReturnDefinition(call);
}
@@ -2413,7 +2430,8 @@
Token::kSET,
arguments,
Array::ZoneHandle(),
- 2)); // Checked argument count.
+ 2, // Checked argument count.
+ owner()->ic_data_array()));
ReturnDefinition(BuildLoadExprTemp());
}
@@ -2778,7 +2796,8 @@
Token::kINDEX,
arguments,
Array::ZoneHandle(),
- checked_argument_count);
+ checked_argument_count,
+ owner()->ic_data_array());
ReturnDefinition(load);
}
}
@@ -2877,7 +2896,8 @@
Token::kASSIGN_INDEX,
arguments,
Array::ZoneHandle(),
- checked_argument_count);
+ checked_argument_count,
+ owner()->ic_data_array());
if (result_is_needed) {
Do(store);
return BuildLoadExprTemp();
diff --git a/runtime/vm/flow_graph_builder.h b/runtime/vm/flow_graph_builder.h
index 950224f..59a752d 100644
--- a/runtime/vm/flow_graph_builder.h
+++ b/runtime/vm/flow_graph_builder.h
@@ -102,11 +102,13 @@
public:
// The inlining context is NULL if not inlining.
FlowGraphBuilder(const ParsedFunction& parsed_function,
+ const Array& ic_data_array,
InlineExitCollector* exit_collector);
FlowGraph* BuildGraph();
const ParsedFunction& parsed_function() const { return parsed_function_; }
+ const Array& ic_data_array() const { return ic_data_array_; }
void Bailout(const char* reason);
@@ -147,6 +149,7 @@
}
const ParsedFunction& parsed_function_;
+ const Array& ic_data_array_;
const intptr_t num_copied_params_;
const intptr_t num_non_copied_params_;
@@ -263,8 +266,6 @@
// May be called only if allocating an object of a parameterized class.
void BuildConstructorTypeArguments(
ConstructorCallNode* node,
- Value** type_arguments,
- Value** instantiator,
ZoneGrowableArray<PushArgumentInstr*>* call_arguments);
void BuildTypecheckPushArguments(
diff --git a/runtime/vm/flow_graph_compiler.cc b/runtime/vm/flow_graph_compiler.cc
index 7b0e38b..a5d50b1 100644
--- a/runtime/vm/flow_graph_compiler.cc
+++ b/runtime/vm/flow_graph_compiler.cc
@@ -219,7 +219,7 @@
continue;
}
- entry->PrepareEntry(this);
+ entry->EmitNativeCode(this);
// Compile all successors until an exit, branch, or a block entry.
for (ForwardInstructionIterator it(entry); !it.Done(); it.Advance()) {
Instruction* instr = it.Current();
@@ -338,9 +338,10 @@
void FlowGraphCompiler::AddDeoptIndexAtCall(intptr_t deopt_id,
intptr_t token_pos) {
ASSERT(is_optimizing());
- CompilerDeoptInfo* info = new CompilerDeoptInfo(deopt_id, kDeoptAtCall);
- ASSERT(pending_deoptimization_env_ != NULL);
- info->set_deoptimization_env(pending_deoptimization_env_);
+ CompilerDeoptInfo* info =
+ new CompilerDeoptInfo(deopt_id,
+ kDeoptAtCall,
+ pending_deoptimization_env_);
info->set_pc_offset(assembler()->CodeSize());
deopt_infos_.Add(info);
}
@@ -399,11 +400,11 @@
Label* FlowGraphCompiler::AddDeoptStub(intptr_t deopt_id,
DeoptReasonId reason) {
- CompilerDeoptInfoWithStub* stub =
- new CompilerDeoptInfoWithStub(deopt_id, reason);
ASSERT(is_optimizing_);
- ASSERT(pending_deoptimization_env_ != NULL);
- stub->set_deoptimization_env(pending_deoptimization_env_);
+ CompilerDeoptInfoWithStub* stub =
+ new CompilerDeoptInfoWithStub(deopt_id,
+ reason,
+ pending_deoptimization_env_);
deopt_infos_.Add(stub);
return stub->entry_label();
}
diff --git a/runtime/vm/flow_graph_compiler.h b/runtime/vm/flow_graph_compiler.h
index f301879..0cb7843 100644
--- a/runtime/vm/flow_graph_compiler.h
+++ b/runtime/vm/flow_graph_compiler.h
@@ -107,11 +107,15 @@
// For deoptimization before instruction use class CompilerDeoptInfoWithStub.
class CompilerDeoptInfo : public ZoneAllocated {
public:
- CompilerDeoptInfo(intptr_t deopt_id, DeoptReasonId reason)
+ CompilerDeoptInfo(intptr_t deopt_id,
+ DeoptReasonId reason,
+ Environment* deopt_env)
: pc_offset_(-1),
deopt_id_(deopt_id),
reason_(reason),
- deoptimization_env_(NULL) {}
+ deopt_env_(deopt_env) {
+ ASSERT(deopt_env != NULL);
+ }
RawDeoptInfo* CreateDeoptInfo(FlowGraphCompiler* compiler,
DeoptInfoBuilder* builder);
@@ -124,11 +128,8 @@
void set_pc_offset(intptr_t offset) { pc_offset_ = offset; }
intptr_t deopt_id() const { return deopt_id_; }
-
DeoptReasonId reason() const { return reason_; }
-
- const Environment* deoptimization_env() const { return deoptimization_env_; }
- void set_deoptimization_env(Environment* env) { deoptimization_env_ = env; }
+ const Environment* deopt_env() const { return deopt_env_; }
private:
void EmitMaterializations(Environment* env, DeoptInfoBuilder* builder);
@@ -139,7 +140,7 @@
intptr_t pc_offset_;
const intptr_t deopt_id_;
const DeoptReasonId reason_;
- Environment* deoptimization_env_;
+ Environment* deopt_env_;
DISALLOW_COPY_AND_ASSIGN(CompilerDeoptInfo);
};
@@ -148,8 +149,9 @@
class CompilerDeoptInfoWithStub : public CompilerDeoptInfo {
public:
CompilerDeoptInfoWithStub(intptr_t deopt_id,
- DeoptReasonId reason)
- : CompilerDeoptInfo(deopt_id, reason), entry_label_() {
+ DeoptReasonId reason,
+ Environment* deopt_env)
+ : CompilerDeoptInfo(deopt_id, reason, deopt_env), entry_label_() {
ASSERT(reason != kDeoptAtCall);
}
diff --git a/runtime/vm/flow_graph_compiler_arm.cc b/runtime/vm/flow_graph_compiler_arm.cc
index f7db7fe..d1e17a8 100644
--- a/runtime/vm/flow_graph_compiler_arm.cc
+++ b/runtime/vm/flow_graph_compiler_arm.cc
@@ -45,17 +45,17 @@
RawDeoptInfo* CompilerDeoptInfo::CreateDeoptInfo(FlowGraphCompiler* compiler,
DeoptInfoBuilder* builder) {
- if (deoptimization_env_ == NULL) return DeoptInfo::null();
+ if (deopt_env_ == NULL) return DeoptInfo::null();
intptr_t stack_height = compiler->StackSize();
- AllocateIncomingParametersRecursive(deoptimization_env_, &stack_height);
+ AllocateIncomingParametersRecursive(deopt_env_, &stack_height);
intptr_t slot_ix = 0;
- Environment* current = deoptimization_env_;
+ Environment* current = deopt_env_;
// Emit all kMaterializeObject instructions describing objects to be
// materialized on the deoptimization as a prefix to the deoptimization info.
- EmitMaterializations(deoptimization_env_, builder);
+ EmitMaterializations(deopt_env_, builder);
// The real frame starts here.
builder->MarkFrameStart();
@@ -150,7 +150,7 @@
__ Bind(entry_label());
if (FLAG_trap_on_deoptimization) __ bkpt(0);
- ASSERT(deoptimization_env() != NULL);
+ ASSERT(deopt_env() != NULL);
__ BranchLink(&StubCode::DeoptimizeLabel());
set_pc_offset(assem->CodeSize());
diff --git a/runtime/vm/flow_graph_compiler_ia32.cc b/runtime/vm/flow_graph_compiler_ia32.cc
index a4af2f8..aa731d9 100644
--- a/runtime/vm/flow_graph_compiler_ia32.cc
+++ b/runtime/vm/flow_graph_compiler_ia32.cc
@@ -48,17 +48,17 @@
RawDeoptInfo* CompilerDeoptInfo::CreateDeoptInfo(FlowGraphCompiler* compiler,
DeoptInfoBuilder* builder) {
- if (deoptimization_env_ == NULL) return DeoptInfo::null();
+ if (deopt_env_ == NULL) return DeoptInfo::null();
intptr_t stack_height = compiler->StackSize();
- AllocateIncomingParametersRecursive(deoptimization_env_, &stack_height);
+ AllocateIncomingParametersRecursive(deopt_env_, &stack_height);
intptr_t slot_ix = 0;
- Environment* current = deoptimization_env_;
+ Environment* current = deopt_env_;
// Emit all kMaterializeObject instructions describing objects to be
// materialized on the deoptimization as a prefix to the deoptimization info.
- EmitMaterializations(deoptimization_env_, builder);
+ EmitMaterializations(deopt_env_, builder);
// The real frame starts here.
builder->MarkFrameStart();
@@ -148,7 +148,7 @@
__ Bind(entry_label());
if (FLAG_trap_on_deoptimization) __ int3();
- ASSERT(deoptimization_env() != NULL);
+ ASSERT(deopt_env() != NULL);
__ call(&StubCode::DeoptimizeLabel());
set_pc_offset(assem->CodeSize());
diff --git a/runtime/vm/flow_graph_compiler_mips.cc b/runtime/vm/flow_graph_compiler_mips.cc
index 27f6d64..4b88a5f 100644
--- a/runtime/vm/flow_graph_compiler_mips.cc
+++ b/runtime/vm/flow_graph_compiler_mips.cc
@@ -60,7 +60,7 @@
__ Bind(entry_label());
if (FLAG_trap_on_deoptimization) __ break_(0);
- ASSERT(deoptimization_env() != NULL);
+ ASSERT(deopt_env() != NULL);
__ BranchLink(&StubCode::DeoptimizeLabel());
set_pc_offset(assem->CodeSize());
diff --git a/runtime/vm/flow_graph_compiler_x64.cc b/runtime/vm/flow_graph_compiler_x64.cc
index 2ae5235..dd764ea 100644
--- a/runtime/vm/flow_graph_compiler_x64.cc
+++ b/runtime/vm/flow_graph_compiler_x64.cc
@@ -46,17 +46,17 @@
RawDeoptInfo* CompilerDeoptInfo::CreateDeoptInfo(FlowGraphCompiler* compiler,
DeoptInfoBuilder* builder) {
- if (deoptimization_env_ == NULL) return DeoptInfo::null();
+ if (deopt_env_ == NULL) return DeoptInfo::null();
intptr_t stack_height = compiler->StackSize();
- AllocateIncomingParametersRecursive(deoptimization_env_, &stack_height);
+ AllocateIncomingParametersRecursive(deopt_env_, &stack_height);
intptr_t slot_ix = 0;
- Environment* current = deoptimization_env_;
+ Environment* current = deopt_env_;
// Emit all kMaterializeObject instructions describing objects to be
// materialized on the deoptimization as a prefix to the deoptimization info.
- EmitMaterializations(deoptimization_env_, builder);
+ EmitMaterializations(deopt_env_, builder);
// The real frame starts here.
builder->MarkFrameStart();
@@ -146,7 +146,7 @@
__ Bind(entry_label());
if (FLAG_trap_on_deoptimization) __ int3();
- ASSERT(deoptimization_env() != NULL);
+ ASSERT(deopt_env() != NULL);
__ call(&StubCode::DeoptimizeLabel());
set_pc_offset(assem->CodeSize());
diff --git a/runtime/vm/flow_graph_inliner.cc b/runtime/vm/flow_graph_inliner.cc
index d3f7d7d..541b3f6 100644
--- a/runtime/vm/flow_graph_inliner.cc
+++ b/runtime/vm/flow_graph_inliner.cc
@@ -465,9 +465,6 @@
}
Isolate* isolate = Isolate::Current();
- // Save and clear IC data.
- const Array& prev_ic_data = Array::Handle(isolate->ic_data_array());
- isolate->set_ic_data_array(Array::null());
// Save and clear deopt id.
const intptr_t prev_deopt_id = isolate->deopt_id();
isolate->set_deopt_id(0);
@@ -487,16 +484,17 @@
}
// Load IC data for the callee.
+ Array& ic_data_array = Array::Handle();
if (function.HasCode()) {
const Code& unoptimized_code =
Code::Handle(function.unoptimized_code());
- isolate->set_ic_data_array(unoptimized_code.ExtractTypeFeedbackArray());
+ ic_data_array = unoptimized_code.ExtractTypeFeedbackArray();
}
// Build the callee graph.
InlineExitCollector* exit_collector =
new InlineExitCollector(caller_graph_, call);
- FlowGraphBuilder builder(*parsed_function, exit_collector);
+ FlowGraphBuilder builder(*parsed_function, ic_data_array, exit_collector);
builder.SetInitialBlockId(caller_graph_->max_block_id());
FlowGraph* callee_graph;
{
@@ -597,7 +595,6 @@
}
isolate->set_long_jump_base(base);
isolate->set_deopt_id(prev_deopt_id);
- isolate->set_ic_data_array(prev_ic_data.raw());
TRACE_INLINING(OS::Print(" Bailout: heuristics with "
"code size: %"Pd", "
"call sites: %"Pd", "
@@ -621,7 +618,6 @@
inlined_size_ += size;
isolate->set_long_jump_base(base);
isolate->set_deopt_id(prev_deopt_id);
- isolate->set_ic_data_array(prev_ic_data.raw());
call_data->callee_graph = callee_graph;
call_data->parameter_stubs = param_stubs;
@@ -634,7 +630,6 @@
isolate->object_store()->clear_sticky_error();
isolate->set_long_jump_base(base);
isolate->set_deopt_id(prev_deopt_id);
- isolate->set_ic_data_array(prev_ic_data.raw());
TRACE_INLINING(OS::Print(" Bailout: %s\n", error.ToErrorCString()));
return false;
}
diff --git a/runtime/vm/flow_graph_optimizer.cc b/runtime/vm/flow_graph_optimizer.cc
index f818958..2da6e02 100644
--- a/runtime/vm/flow_graph_optimizer.cc
+++ b/runtime/vm/flow_graph_optimizer.cc
@@ -5984,7 +5984,8 @@
new EqualityCompareInstr(equality_compare->token_pos(),
comparison->kind(),
left,
- right);
+ right,
+ Array::Handle());
new_equality_compare->set_ic_data(equality_compare->ic_data());
new_comparison = new_equality_compare;
} else {
@@ -5994,7 +5995,8 @@
new RelationalOpInstr(relational_op->token_pos(),
comparison->kind(),
left,
- right);
+ right,
+ Array::Handle());
new_relational_op->set_ic_data(relational_op->ic_data());
new_comparison = new_relational_op;
}
diff --git a/runtime/vm/flow_graph_type_propagator.cc b/runtime/vm/flow_graph_type_propagator.cc
index f709124..d096872 100644
--- a/runtime/vm/flow_graph_type_propagator.cc
+++ b/runtime/vm/flow_graph_type_propagator.cc
@@ -736,7 +736,7 @@
if (value().IsInstance()) {
return CompileType::Create(
- Class::Handle(value().clazz()).id(),
+ value().GetClassId(),
AbstractType::ZoneHandle(Instance::Cast(value()).GetType()));
} else {
ASSERT(value().IsAbstractTypeArguments());
diff --git a/runtime/vm/intermediate_language.cc b/runtime/vm/intermediate_language.cc
index 91eca39..ed56e35 100644
--- a/runtime/vm/intermediate_language.cc
+++ b/runtime/vm/intermediate_language.cc
@@ -42,6 +42,17 @@
}
+ICData* Instruction::GetICData(const Array& ic_data_array) const {
+ ICData& ic_data = ICData::ZoneHandle();
+ // The deopt_id can be outside the range of the IC data array for
+ // computations added in the optimizing compiler.
+ if (!ic_data_array.IsNull() && (deopt_id_ < ic_data_array.Length())) {
+ ic_data ^= ic_data_array.At(deopt_id_);
+ }
+ return &ic_data;
+}
+
+
intptr_t Instruction::Hashcode() const {
intptr_t result = tag();
for (intptr_t i = 0; i < InputCount(); ++i) {
@@ -1396,56 +1407,13 @@
}
-// Shared code generation methods (EmitNativeCode, MakeLocationSummary, and
-// PrepareEntry). Only assembly code that can be shared across all architectures
-// can be used. Machine specific register allocation and code generation
-// is located in intermediate_language_<arch>.cc
+// Shared code generation methods (EmitNativeCode and
+// MakeLocationSummary). Only assembly code that can be shared across all
+// architectures can be used. Machine specific register allocation and code
+// generation is located in intermediate_language_<arch>.cc
#define __ compiler->assembler()->
-void GraphEntryInstr::PrepareEntry(FlowGraphCompiler* compiler) {
- // Nothing to do.
-}
-
-
-void JoinEntryInstr::PrepareEntry(FlowGraphCompiler* compiler) {
- if (!compiler->is_optimizing()) {
- compiler->AddCurrentDescriptor(PcDescriptors::kDeopt,
- deopt_id_,
- Scanner::kDummyTokenIndex);
- }
- __ Bind(compiler->GetJumpLabel(this));
- if (HasParallelMove()) {
- compiler->parallel_move_resolver()->EmitNativeCode(parallel_move());
- }
-}
-
-
-void TargetEntryInstr::PrepareEntry(FlowGraphCompiler* compiler) {
- if (!compiler->is_optimizing()) {
- compiler->AddCurrentDescriptor(PcDescriptors::kDeopt,
- deopt_id_,
- Scanner::kDummyTokenIndex);
- }
- __ Bind(compiler->GetJumpLabel(this));
- if (HasParallelMove()) {
- compiler->parallel_move_resolver()->EmitNativeCode(parallel_move());
- }
-}
-
-
-void CatchBlockEntryInstr::PrepareEntry(FlowGraphCompiler* compiler) {
- __ Bind(compiler->GetJumpLabel(this));
- compiler->AddExceptionHandler(catch_try_index(),
- try_index(),
- compiler->assembler()->CodeSize(),
- catch_handler_types_);
- if (HasParallelMove()) {
- compiler->parallel_move_resolver()->EmitNativeCode(parallel_move());
- }
-}
-
-
LocationSummary* GraphEntryInstr::MakeLocationSummary() const {
UNREACHABLE();
return NULL;
@@ -1453,7 +1421,7 @@
void GraphEntryInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
- UNREACHABLE();
+ // Nothing to do.
}
@@ -1464,7 +1432,15 @@
void JoinEntryInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
- UNREACHABLE();
+ if (!compiler->is_optimizing()) {
+ compiler->AddCurrentDescriptor(PcDescriptors::kDeopt,
+ deopt_id_,
+ Scanner::kDummyTokenIndex);
+ }
+ __ Bind(compiler->GetJumpLabel(this));
+ if (HasParallelMove()) {
+ compiler->parallel_move_resolver()->EmitNativeCode(parallel_move());
+ }
}
@@ -1475,7 +1451,15 @@
void TargetEntryInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
- UNREACHABLE();
+ if (!compiler->is_optimizing()) {
+ compiler->AddCurrentDescriptor(PcDescriptors::kDeopt,
+ deopt_id_,
+ Scanner::kDummyTokenIndex);
+ }
+ __ Bind(compiler->GetJumpLabel(this));
+ if (HasParallelMove()) {
+ compiler->parallel_move_resolver()->EmitNativeCode(parallel_move());
+ }
}
@@ -1486,7 +1470,14 @@
void CatchBlockEntryInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
- UNREACHABLE();
+ __ Bind(compiler->GetJumpLabel(this));
+ compiler->AddExceptionHandler(catch_try_index(),
+ try_index(),
+ compiler->assembler()->CodeSize(),
+ catch_handler_types_);
+ if (HasParallelMove()) {
+ compiler->parallel_move_resolver()->EmitNativeCode(parallel_move());
+ }
}
diff --git a/runtime/vm/intermediate_language.h b/runtime/vm/intermediate_language.h
index f881959..42c8470 100644
--- a/runtime/vm/intermediate_language.h
+++ b/runtime/vm/intermediate_language.h
@@ -646,6 +646,8 @@
return deopt_id_;
}
+ ICData* GetICData(const Array& ic_data_array) const;
+
bool IsBlockEntry() { return (AsBlockEntry() != NULL); }
virtual BlockEntryInstr* AsBlockEntry() { return NULL; }
@@ -1070,7 +1072,6 @@
virtual intptr_t PredecessorCount() const = 0;
virtual BlockEntryInstr* PredecessorAt(intptr_t index) const = 0;
- virtual void PrepareEntry(FlowGraphCompiler* compiler) = 0;
intptr_t preorder_number() const { return preorder_number_; }
void set_preorder_number(intptr_t number) { preorder_number_ = number; }
@@ -1292,8 +1293,6 @@
CatchBlockEntryInstr* GetCatchEntry(intptr_t index);
- virtual void PrepareEntry(FlowGraphCompiler* compiler);
-
GrowableArray<Definition*>* initial_definitions() {
return &initial_definitions_;
}
@@ -1359,8 +1358,6 @@
ZoneGrowableArray<PhiInstr*>* phis() const { return phis_; }
- virtual void PrepareEntry(FlowGraphCompiler* compiler);
-
void InsertPhi(intptr_t var_index, intptr_t var_count);
void RemoveDeadPhis(Definition* replacement);
@@ -1429,8 +1426,6 @@
return predecessor_;
}
- virtual void PrepareEntry(FlowGraphCompiler* compiler);
-
virtual void PrintTo(BufferFormatter* f) const;
private:
@@ -1478,8 +1473,6 @@
return &initial_definitions_;
}
- virtual void PrepareEntry(FlowGraphCompiler* compiler);
-
virtual void PrintTo(BufferFormatter* f) const;
private:
@@ -2600,8 +2593,9 @@
Token::Kind token_kind,
ZoneGrowableArray<PushArgumentInstr*>* arguments,
const Array& argument_names,
- intptr_t checked_argument_count)
- : ic_data_(Isolate::Current()->GetICDataForDeoptId(deopt_id())),
+ intptr_t checked_argument_count,
+ const Array& ic_data_array)
+ : ic_data_(GetICData(ic_data_array)),
token_pos_(token_pos),
function_name_(function_name),
token_kind_(token_kind),
@@ -2842,12 +2836,12 @@
EqualityCompareInstr(intptr_t token_pos,
Token::Kind kind,
Value* left,
- Value* right)
+ Value* right,
+ const Array& ic_data_array)
: ComparisonInstr(kind, left, right),
+ ic_data_(GetICData(ic_data_array)),
token_pos_(token_pos),
receiver_class_id_(kIllegalCid) {
- // deopt_id() checks receiver_class_id_ value.
- ic_data_ = Isolate::Current()->GetICDataForDeoptId(deopt_id());
ASSERT((kind == Token::kEQ) || (kind == Token::kNE));
}
@@ -2921,12 +2915,12 @@
RelationalOpInstr(intptr_t token_pos,
Token::Kind kind,
Value* left,
- Value* right)
+ Value* right,
+ const Array& ic_data_array)
: ComparisonInstr(kind, left, right),
+ ic_data_(GetICData(ic_data_array)),
token_pos_(token_pos),
operands_class_id_(kIllegalCid) {
- // deopt_id() checks operands_class_id_ value.
- ic_data_ = Isolate::Current()->GetICDataForDeoptId(deopt_id());
ASSERT(Token::IsRelationalOperator(kind));
}
@@ -3719,18 +3713,16 @@
};
-class AllocateObjectWithBoundsCheckInstr : public TemplateDefinition<2> {
+class AllocateObjectWithBoundsCheckInstr : public TemplateDefinition<0> {
public:
- AllocateObjectWithBoundsCheckInstr(ConstructorCallNode* node,
- Value* type_arguments,
- Value* instantiator)
+ explicit AllocateObjectWithBoundsCheckInstr(ConstructorCallNode* node)
: ast_node_(*node) {
- SetInputAt(0, type_arguments);
- SetInputAt(1, instantiator);
}
DECLARE_INSTRUCTION(AllocateObjectWithBoundsCheck)
+ virtual intptr_t ArgumentCount() const { return 4; }
+
const Function& constructor() const { return ast_node_.constructor(); }
intptr_t token_pos() const { return ast_node_.token_pos(); }
diff --git a/runtime/vm/intermediate_language_arm.cc b/runtime/vm/intermediate_language_arm.cc
index 9d93594..ecbaf96 100644
--- a/runtime/vm/intermediate_language_arm.cc
+++ b/runtime/vm/intermediate_language_arm.cc
@@ -1405,9 +1405,9 @@
LocationSummary* StoreInstanceFieldInstr::MakeLocationSummary() const {
const intptr_t kNumInputs = 2;
- const intptr_t num_temps = 0;
+ const intptr_t kNumTemps = 0;
LocationSummary* summary =
- new LocationSummary(kNumInputs, num_temps, LocationSummary::kNoCall);
+ new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall);
summary->set_in(0, Location::RequiresRegister());
summary->set_in(1, ShouldEmitStoreBarrier()
? Location::WritableRegister()
@@ -1610,27 +1610,24 @@
// instantiator_reg is the instantiator type argument vector, i.e. an
// AbstractTypeArguments object (or null).
- if (!type_arguments().IsUninstantiatedIdentity() &&
- !type_arguments().CanShareInstantiatorTypeArguments(
- instantiator_class())) {
- // If the instantiator is null and if the type argument vector
- // instantiated from null becomes a vector of dynamic, then use null as
- // the type arguments.
- Label type_arguments_instantiated;
- const intptr_t len = type_arguments().Length();
- if (type_arguments().IsRawInstantiatedRaw(len)) {
- __ CompareImmediate(instantiator_reg,
- reinterpret_cast<intptr_t>(Object::null()));
- __ b(&type_arguments_instantiated, EQ);
- }
- // Instantiate non-null type arguments.
- // In the non-factory case, we rely on the allocation stub to
- // instantiate the type arguments.
- __ LoadObject(result_reg, type_arguments());
- // result_reg: uninstantiated type arguments.
- __ Bind(&type_arguments_instantiated);
- }
- ASSERT(instantiator_reg == result_reg);
+ ASSERT(!type_arguments().IsUninstantiatedIdentity() &&
+ !type_arguments().CanShareInstantiatorTypeArguments(
+ instantiator_class()));
+ // If the instantiator is null and if the type argument vector
+ // instantiated from null becomes a vector of dynamic, then use null as
+ // the type arguments.
+ Label type_arguments_instantiated;
+ ASSERT(type_arguments().IsRawInstantiatedRaw(type_arguments().Length()));
+ __ CompareImmediate(instantiator_reg,
+ reinterpret_cast<intptr_t>(Object::null()));
+ __ b(&type_arguments_instantiated, EQ);
+ // Instantiate non-null type arguments.
+ // In the non-factory case, we rely on the allocation stub to
+ // instantiate the type arguments.
+ __ LoadObject(result_reg, type_arguments());
+ // result_reg: uninstantiated type arguments.
+ __ Bind(&type_arguments_instantiated);
+
// result_reg: uninstantiated or instantiated type arguments.
}
@@ -1654,30 +1651,23 @@
// instantiator_reg is the instantiator AbstractTypeArguments object
// (or null).
- if (type_arguments().IsUninstantiatedIdentity() ||
- type_arguments().CanShareInstantiatorTypeArguments(
- instantiator_class())) {
- // The instantiator was used in VisitExtractConstructorTypeArguments as the
- // instantiated type arguments, no proper instantiator needed.
- __ LoadImmediate(instantiator_reg,
- Smi::RawValue(StubCode::kNoInstantiator));
- } else {
- // If the instantiator is null and if the type argument vector
- // instantiated from null becomes a vector of dynamic, then use null as
- // the type arguments and do not pass the instantiator.
- const intptr_t len = type_arguments().Length();
- if (type_arguments().IsRawInstantiatedRaw(len)) {
- Label instantiator_not_null;
- __ CompareImmediate(instantiator_reg,
- reinterpret_cast<intptr_t>(Object::null()));
- __ b(&instantiator_not_null, NE);
- // Null was used in VisitExtractConstructorTypeArguments as the
- // instantiated type arguments, no proper instantiator needed.
- __ LoadImmediate(instantiator_reg,
- Smi::RawValue(StubCode::kNoInstantiator));
- __ Bind(&instantiator_not_null);
- }
- }
+ ASSERT(!type_arguments().IsUninstantiatedIdentity() &&
+ !type_arguments().CanShareInstantiatorTypeArguments(
+ instantiator_class()));
+
+ // If the instantiator is null and if the type argument vector
+ // instantiated from null becomes a vector of dynamic, then use null as
+ // the type arguments and do not pass the instantiator.
+ ASSERT(type_arguments().IsRawInstantiatedRaw(type_arguments().Length()));
+ Label instantiator_not_null;
+ __ CompareImmediate(instantiator_reg,
+ reinterpret_cast<intptr_t>(Object::null()));
+ __ b(&instantiator_not_null, NE);
+ // Null was used in VisitExtractConstructorTypeArguments as the
+ // instantiated type arguments, no proper instantiator needed.
+ __ LoadImmediate(instantiator_reg,
+ Smi::RawValue(StubCode::kNoInstantiator));
+ __ Bind(&instantiator_not_null);
// instantiator_reg: instantiator or kNoInstantiator.
}
@@ -2640,9 +2630,9 @@
void GotoInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
- // Add deoptimization descriptor for deoptimizing instructions
- // that may be inserted before this instruction.
if (!compiler->is_optimizing()) {
+ // Add deoptimization descriptor for deoptimizing instructions that may
+ // be inserted before this instruction.
compiler->AddCurrentDescriptor(PcDescriptors::kDeopt,
GetDeoptId(),
0); // No token position.
diff --git a/runtime/vm/intermediate_language_ia32.cc b/runtime/vm/intermediate_language_ia32.cc
index 8e43726..6569c52 100644
--- a/runtime/vm/intermediate_language_ia32.cc
+++ b/runtime/vm/intermediate_language_ia32.cc
@@ -1704,9 +1704,9 @@
LocationSummary* StoreInstanceFieldInstr::MakeLocationSummary() const {
const intptr_t kNumInputs = 2;
- const intptr_t num_temps = 0;
+ const intptr_t kNumTemps = 0;
LocationSummary* summary =
- new LocationSummary(kNumInputs, num_temps, LocationSummary::kNoCall);
+ new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall);
summary->set_in(0, Location::RequiresRegister());
summary->set_in(1, ShouldEmitStoreBarrier()
? Location::WritableRegister()
@@ -1828,37 +1828,19 @@
LocationSummary*
AllocateObjectWithBoundsCheckInstr::MakeLocationSummary() const {
- const intptr_t kNumInputs = 2;
- const intptr_t kNumTemps = 0;
- LocationSummary* locs =
- new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kCall);
- locs->set_in(0, Location::RegisterLocation(EAX));
- locs->set_in(1, Location::RegisterLocation(ECX));
- locs->set_out(Location::RegisterLocation(EAX));
- return locs;
+ return MakeCallSummary();
}
void AllocateObjectWithBoundsCheckInstr::EmitNativeCode(
FlowGraphCompiler* compiler) {
- const Class& cls = Class::ZoneHandle(constructor().Owner());
- Register type_arguments = locs()->in(0).reg();
- Register instantiator_type_arguments = locs()->in(1).reg();
- Register result = locs()->out().reg();
-
- // Push the result place holder initialized to NULL.
- __ PushObject(Object::ZoneHandle());
- __ PushObject(cls);
- __ pushl(type_arguments);
- __ pushl(instantiator_type_arguments);
compiler->GenerateCallRuntime(token_pos(),
deopt_id(),
kAllocateObjectWithBoundsCheckRuntimeEntry,
locs());
- // Pop instantiator type arguments, type arguments, and class.
- // source location.
__ Drop(3);
- __ popl(result); // Pop new instance.
+ ASSERT(locs()->out().reg() == EAX);
+ __ popl(EAX); // Pop new instance.
}
@@ -1947,28 +1929,25 @@
// instantiator_reg is the instantiator type argument vector, i.e. an
// AbstractTypeArguments object (or null).
- if (!type_arguments().IsUninstantiatedIdentity() &&
- !type_arguments().CanShareInstantiatorTypeArguments(
- instantiator_class())) {
- // If the instantiator is null and if the type argument vector
- // instantiated from null becomes a vector of dynamic, then use null as
- // the type arguments.
- Label type_arguments_instantiated;
- const intptr_t len = type_arguments().Length();
- if (type_arguments().IsRawInstantiatedRaw(len)) {
- const Immediate& raw_null =
- Immediate(reinterpret_cast<intptr_t>(Object::null()));
- __ cmpl(instantiator_reg, raw_null);
- __ j(EQUAL, &type_arguments_instantiated, Assembler::kNearJump);
- }
- // Instantiate non-null type arguments.
- // In the non-factory case, we rely on the allocation stub to
- // instantiate the type arguments.
- __ LoadObject(result_reg, type_arguments());
- // result_reg: uninstantiated type arguments.
- __ Bind(&type_arguments_instantiated);
- }
- ASSERT(instantiator_reg == result_reg);
+ ASSERT(!type_arguments().IsUninstantiatedIdentity() &&
+ !type_arguments().CanShareInstantiatorTypeArguments(
+ instantiator_class()));
+ // If the instantiator is null and if the type argument vector
+ // instantiated from null becomes a vector of dynamic, then use null as
+ // the type arguments.
+ ASSERT(type_arguments().IsRawInstantiatedRaw(type_arguments().Length()));
+ Label type_arguments_instantiated;
+ const Immediate& raw_null =
+ Immediate(reinterpret_cast<intptr_t>(Object::null()));
+ __ cmpl(instantiator_reg, raw_null);
+ __ j(EQUAL, &type_arguments_instantiated, Assembler::kNearJump);
+ // Instantiate non-null type arguments.
+ // In the non-factory case, we rely on the allocation stub to
+ // instantiate the type arguments.
+ __ LoadObject(result_reg, type_arguments());
+ // result_reg: uninstantiated type arguments.
+
+ __ Bind(&type_arguments_instantiated);
// result_reg: uninstantiated or instantiated type arguments.
}
@@ -1992,31 +1971,24 @@
// instantiator_reg is the instantiator AbstractTypeArguments object
// (or null).
- if (type_arguments().IsUninstantiatedIdentity() ||
- type_arguments().CanShareInstantiatorTypeArguments(
- instantiator_class())) {
- // The instantiator was used in VisitExtractConstructorTypeArguments as the
- // instantiated type arguments, no proper instantiator needed.
- __ movl(instantiator_reg,
- Immediate(Smi::RawValue(StubCode::kNoInstantiator)));
- } else {
- // If the instantiator is null and if the type argument vector
- // instantiated from null becomes a vector of dynamic, then use null as
- // the type arguments and do not pass the instantiator.
- const intptr_t len = type_arguments().Length();
- if (type_arguments().IsRawInstantiatedRaw(len)) {
- const Immediate& raw_null =
- Immediate(reinterpret_cast<intptr_t>(Object::null()));
- Label instantiator_not_null;
- __ cmpl(instantiator_reg, raw_null);
- __ j(NOT_EQUAL, &instantiator_not_null, Assembler::kNearJump);
- // Null was used in VisitExtractConstructorTypeArguments as the
- // instantiated type arguments, no proper instantiator needed.
- __ movl(instantiator_reg,
- Immediate(Smi::RawValue(StubCode::kNoInstantiator)));
- __ Bind(&instantiator_not_null);
- }
- }
+ ASSERT(!type_arguments().IsUninstantiatedIdentity() &&
+ !type_arguments().CanShareInstantiatorTypeArguments(
+ instantiator_class()));
+
+ // If the instantiator is null and if the type argument vector
+ // instantiated from null becomes a vector of dynamic, then use null as
+ // the type arguments and do not pass the instantiator.
+ ASSERT(type_arguments().IsRawInstantiatedRaw(type_arguments().Length()));
+ const Immediate& raw_null =
+ Immediate(reinterpret_cast<intptr_t>(Object::null()));
+ Label instantiator_not_null;
+ __ cmpl(instantiator_reg, raw_null);
+ __ j(NOT_EQUAL, &instantiator_not_null, Assembler::kNearJump);
+ // Null was used in VisitExtractConstructorTypeArguments as the
+ // instantiated type arguments, no proper instantiator needed.
+ __ movl(instantiator_reg,
+ Immediate(Smi::RawValue(StubCode::kNoInstantiator)));
+ __ Bind(&instantiator_not_null);
// instantiator_reg: instantiator or kNoInstantiator.
}
@@ -4290,9 +4262,9 @@
void GotoInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
- // Add deoptimization descriptor for deoptimizing instructions
- // that may be inserted before this instruction.
if (!compiler->is_optimizing()) {
+ // Add deoptimization descriptor for deoptimizing instructions that may
+ // be inserted before this instruction.
compiler->AddCurrentDescriptor(PcDescriptors::kDeopt,
GetDeoptId(),
0); // No token position.
diff --git a/runtime/vm/intermediate_language_mips.cc b/runtime/vm/intermediate_language_mips.cc
index c07ff89..f9e270b 100644
--- a/runtime/vm/intermediate_language_mips.cc
+++ b/runtime/vm/intermediate_language_mips.cc
@@ -1342,9 +1342,9 @@
LocationSummary* StoreInstanceFieldInstr::MakeLocationSummary() const {
const intptr_t kNumInputs = 2;
- const intptr_t num_temps = 0;
+ const intptr_t kNumTemps = 0;
LocationSummary* summary =
- new LocationSummary(kNumInputs, num_temps, LocationSummary::kNoCall);
+ new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall);
summary->set_in(0, Location::RequiresRegister());
summary->set_in(1, ShouldEmitStoreBarrier()
? Location::WritableRegister()
@@ -1556,27 +1556,24 @@
// instantiator_reg is the instantiator type argument vector, i.e. an
// AbstractTypeArguments object (or null).
- if (!type_arguments().IsUninstantiatedIdentity() &&
- !type_arguments().CanShareInstantiatorTypeArguments(
- instantiator_class())) {
- // If the instantiator is null and if the type argument vector
- // instantiated from null becomes a vector of dynamic, then use null as
- // the type arguments.
- Label type_arguments_instantiated;
- const intptr_t len = type_arguments().Length();
- if (type_arguments().IsRawInstantiatedRaw(len)) {
- __ BranchEqual(instantiator_reg,
- reinterpret_cast<intptr_t>(Object::null()),
- &type_arguments_instantiated);
- }
- // Instantiate non-null type arguments.
- // In the non-factory case, we rely on the allocation stub to
- // instantiate the type arguments.
- __ LoadObject(result_reg, type_arguments());
- // result_reg: uninstantiated type arguments.
- __ Bind(&type_arguments_instantiated);
- }
- ASSERT(instantiator_reg == result_reg);
+ ASSERT(!type_arguments().IsUninstantiatedIdentity() &&
+ !type_arguments().CanShareInstantiatorTypeArguments(
+ instantiator_class()));
+ // If the instantiator is null and if the type argument vector
+ // instantiated from null becomes a vector of dynamic, then use null as
+ // the type arguments.
+ Label type_arguments_instantiated;
+ ASSERT(type_arguments().IsRawInstantiatedRaw(type_arguments().Length()));
+ __ BranchEqual(instantiator_reg,
+ reinterpret_cast<intptr_t>(Object::null()),
+ &type_arguments_instantiated);
+ // Instantiate non-null type arguments.
+ // In the non-factory case, we rely on the allocation stub to
+ // instantiate the type arguments.
+ __ LoadObject(result_reg, type_arguments());
+ // result_reg: uninstantiated type arguments.
+ __ Bind(&type_arguments_instantiated);
+
// result_reg: uninstantiated or instantiated type arguments.
}
@@ -1600,29 +1597,22 @@
// instantiator_reg is the instantiator AbstractTypeArguments object
// (or null).
- if (type_arguments().IsUninstantiatedIdentity() ||
- type_arguments().CanShareInstantiatorTypeArguments(
- instantiator_class())) {
- // The instantiator was used in VisitExtractConstructorTypeArguments as the
- // instantiated type arguments, no proper instantiator needed.
- __ LoadImmediate(instantiator_reg,
- Smi::RawValue(StubCode::kNoInstantiator));
- } else {
- // If the instantiator is null and if the type argument vector
- // instantiated from null becomes a vector of dynamic, then use null as
- // the type arguments and do not pass the instantiator.
- const intptr_t len = type_arguments().Length();
- if (type_arguments().IsRawInstantiatedRaw(len)) {
- Label instantiator_not_null;
- __ BranchNotEqual(instantiator_reg,
- reinterpret_cast<intptr_t>(Object::null()), &instantiator_not_null);
- // Null was used in VisitExtractConstructorTypeArguments as the
- // instantiated type arguments, no proper instantiator needed.
- __ LoadImmediate(instantiator_reg,
- Smi::RawValue(StubCode::kNoInstantiator));
- __ Bind(&instantiator_not_null);
- }
- }
+ ASSERT(!type_arguments().IsUninstantiatedIdentity() &&
+ !type_arguments().CanShareInstantiatorTypeArguments(
+ instantiator_class()));
+
+ // If the instantiator is null and if the type argument vector
+ // instantiated from null becomes a vector of dynamic, then use null as
+ // the type arguments and do not pass the instantiator.
+ ASSERT(type_arguments().IsRawInstantiatedRaw(type_arguments().Length()));
+ Label instantiator_not_null;
+ __ BranchNotEqual(instantiator_reg,
+ reinterpret_cast<intptr_t>(Object::null()), &instantiator_not_null);
+ // Null was used in VisitExtractConstructorTypeArguments as the
+ // instantiated type arguments, no proper instantiator needed.
+ __ LoadImmediate(instantiator_reg,
+ Smi::RawValue(StubCode::kNoInstantiator));
+ __ Bind(&instantiator_not_null);
// instantiator_reg: instantiator or kNoInstantiator.
}
@@ -2618,9 +2608,9 @@
void GotoInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
__ TraceSimMsg("GotoInstr");
- // Add deoptimization descriptor for deoptimizing instructions
- // that may be inserted before this instruction.
if (!compiler->is_optimizing()) {
+ // Add deoptimization descriptor for deoptimizing instructions that may
+ // be inserted before this instruction.
compiler->AddCurrentDescriptor(PcDescriptors::kDeopt,
GetDeoptId(),
0); // No token position.
diff --git a/runtime/vm/intermediate_language_x64.cc b/runtime/vm/intermediate_language_x64.cc
index f089bed..88557a7 100644
--- a/runtime/vm/intermediate_language_x64.cc
+++ b/runtime/vm/intermediate_language_x64.cc
@@ -1689,9 +1689,9 @@
LocationSummary* StoreInstanceFieldInstr::MakeLocationSummary() const {
const intptr_t kNumInputs = 2;
- const intptr_t num_temps = 0;
+ const intptr_t kNumTemps = 0;
LocationSummary* summary =
- new LocationSummary(kNumInputs, num_temps, LocationSummary::kNoCall);
+ new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall);
summary->set_in(0, Location::RequiresRegister());
summary->set_in(1, ShouldEmitStoreBarrier()
? Location::WritableRegister()
@@ -1811,36 +1811,19 @@
LocationSummary*
AllocateObjectWithBoundsCheckInstr::MakeLocationSummary() const {
- const intptr_t kNumInputs = 2;
- const intptr_t kNumTemps = 0;
- LocationSummary* locs =
- new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kCall);
- locs->set_in(0, Location::RegisterLocation(RAX));
- locs->set_in(1, Location::RegisterLocation(RCX));
- locs->set_out(Location::RegisterLocation(RAX));
- return locs;
+ return MakeCallSummary();
}
void AllocateObjectWithBoundsCheckInstr::EmitNativeCode(
FlowGraphCompiler* compiler) {
- const Class& cls = Class::ZoneHandle(constructor().Owner());
- Register type_arguments = locs()->in(0).reg();
- Register instantiator_type_arguments = locs()->in(1).reg();
- Register result = locs()->out().reg();
-
- // Push the result place holder initialized to NULL.
- __ PushObject(Object::ZoneHandle());
- __ PushObject(cls);
- __ pushq(type_arguments);
- __ pushq(instantiator_type_arguments);
compiler->GenerateCallRuntime(token_pos(),
deopt_id(),
kAllocateObjectWithBoundsCheckRuntimeEntry,
locs());
- // Pop instantiator type arguments, type arguments, and class.
__ Drop(3);
- __ popq(result); // Pop new instance.
+ ASSERT(locs()->out().reg() == RAX);
+ __ popq(RAX); // Pop new instance.
}
@@ -1929,28 +1912,25 @@
// instantiator_reg is the instantiator type argument vector, i.e. an
// AbstractTypeArguments object (or null).
- if (!type_arguments().IsUninstantiatedIdentity() &&
- !type_arguments().CanShareInstantiatorTypeArguments(
- instantiator_class())) {
- // If the instantiator is null and if the type argument vector
- // instantiated from null becomes a vector of dynamic, then use null as
- // the type arguments.
- Label type_arguments_instantiated;
- const intptr_t len = type_arguments().Length();
- if (type_arguments().IsRawInstantiatedRaw(len)) {
- const Immediate& raw_null =
- Immediate(reinterpret_cast<intptr_t>(Object::null()));
- __ cmpq(instantiator_reg, raw_null);
- __ j(EQUAL, &type_arguments_instantiated, Assembler::kNearJump);
- }
- // Instantiate non-null type arguments.
- // In the non-factory case, we rely on the allocation stub to
- // instantiate the type arguments.
- __ LoadObject(result_reg, type_arguments());
- // result_reg: uninstantiated type arguments.
- __ Bind(&type_arguments_instantiated);
- }
- ASSERT(instantiator_reg == result_reg);
+ ASSERT(!type_arguments().IsUninstantiatedIdentity() &&
+ !type_arguments().CanShareInstantiatorTypeArguments(
+ instantiator_class()));
+ // If the instantiator is null and if the type argument vector
+ // instantiated from null becomes a vector of dynamic, then use null as
+ // the type arguments.
+ Label type_arguments_instantiated;
+ ASSERT(type_arguments().IsRawInstantiatedRaw(type_arguments().Length()));
+ const Immediate& raw_null =
+ Immediate(reinterpret_cast<intptr_t>(Object::null()));
+ __ cmpq(instantiator_reg, raw_null);
+ __ j(EQUAL, &type_arguments_instantiated, Assembler::kNearJump);
+ // Instantiate non-null type arguments.
+ // In the non-factory case, we rely on the allocation stub to
+ // instantiate the type arguments.
+ __ LoadObject(result_reg, type_arguments());
+ // result_reg: uninstantiated type arguments.
+
+ __ Bind(&type_arguments_instantiated);
// result_reg: uninstantiated or instantiated type arguments.
}
@@ -1974,31 +1954,24 @@
// instantiator_reg is the instantiator AbstractTypeArguments object
// (or null).
- if (type_arguments().IsUninstantiatedIdentity() ||
- type_arguments().CanShareInstantiatorTypeArguments(
- instantiator_class())) {
- // The instantiator was used in VisitExtractConstructorTypeArguments as the
- // instantiated type arguments, no proper instantiator needed.
- __ movq(instantiator_reg,
- Immediate(Smi::RawValue(StubCode::kNoInstantiator)));
- } else {
- // If the instantiator is null and if the type argument vector
- // instantiated from null becomes a vector of dynamic, then use null as
- // the type arguments and do not pass the instantiator.
- const intptr_t len = type_arguments().Length();
- if (type_arguments().IsRawInstantiatedRaw(len)) {
- const Immediate& raw_null =
- Immediate(reinterpret_cast<intptr_t>(Object::null()));
- Label instantiator_not_null;
- __ cmpq(instantiator_reg, raw_null);
- __ j(NOT_EQUAL, &instantiator_not_null, Assembler::kNearJump);
- // Null was used in VisitExtractConstructorTypeArguments as the
- // instantiated type arguments, no proper instantiator needed.
- __ movq(instantiator_reg,
- Immediate(Smi::RawValue(StubCode::kNoInstantiator)));
- __ Bind(&instantiator_not_null);
- }
- }
+ ASSERT(!type_arguments().IsUninstantiatedIdentity() &&
+ !type_arguments().CanShareInstantiatorTypeArguments(
+ instantiator_class()));
+
+ // If the instantiator is null and if the type argument vector
+ // instantiated from null becomes a vector of dynamic, then use null as
+ // the type arguments and do not pass the instantiator.
+ ASSERT(type_arguments().IsRawInstantiatedRaw(type_arguments().Length()));
+ const Immediate& raw_null =
+ Immediate(reinterpret_cast<intptr_t>(Object::null()));
+ Label instantiator_not_null;
+ __ cmpq(instantiator_reg, raw_null);
+ __ j(NOT_EQUAL, &instantiator_not_null, Assembler::kNearJump);
+ // Null was used in VisitExtractConstructorTypeArguments as the
+ // instantiated type arguments, no proper instantiator needed.
+ __ movq(instantiator_reg,
+ Immediate(Smi::RawValue(StubCode::kNoInstantiator)));
+ __ Bind(&instantiator_not_null);
// instantiator_reg: instantiator or kNoInstantiator.
}
@@ -4090,9 +4063,9 @@
void GotoInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
- // Add deoptimization descriptor for deoptimizing instructions
- // that may be inserted before this instruction.
if (!compiler->is_optimizing()) {
+ // Add deoptimization descriptor for deoptimizing instructions that may
+ // be inserted before this instruction.
compiler->AddCurrentDescriptor(PcDescriptors::kDeopt,
GetDeoptId(),
0); // No token position.
diff --git a/runtime/vm/intrinsifier.h b/runtime/vm/intrinsifier.h
index 4828657..d55d3c1 100644
--- a/runtime/vm/intrinsifier.h
+++ b/runtime/vm/intrinsifier.h
@@ -91,6 +91,7 @@
V(::, sqrt, Math_sqrt, 1662640002) \
V(::, sin, Math_sin, 1273932041) \
V(::, cos, Math_cos, 1749547468) \
+ V(_Random, _nextState, Random_nextState, 77315414) \
#define TYPED_DATA_LIB_INTRINSIC_LIST(V) \
diff --git a/runtime/vm/intrinsifier_arm.cc b/runtime/vm/intrinsifier_arm.cc
index d263973..49d87c0 100644
--- a/runtime/vm/intrinsifier_arm.cc
+++ b/runtime/vm/intrinsifier_arm.cc
@@ -311,6 +311,11 @@
}
+bool Intrinsifier::Random_nextState(Assembler* assembler) {
+ return false;
+}
+
+
bool Intrinsifier::Object_equal(Assembler* assembler) {
return false;
}
diff --git a/runtime/vm/intrinsifier_ia32.cc b/runtime/vm/intrinsifier_ia32.cc
index 097da1b..8d5ff5a 100644
--- a/runtime/vm/intrinsifier_ia32.cc
+++ b/runtime/vm/intrinsifier_ia32.cc
@@ -14,6 +14,7 @@
#include "vm/intrinsifier.h"
#include "vm/assembler.h"
+#include "vm/flow_graph_compiler.h"
#include "vm/object.h"
#include "vm/object_store.h"
#include "vm/os.h"
@@ -1427,6 +1428,52 @@
}
+// var state = ((_A * (_state[kSTATE_LO])) + _state[kSTATE_HI]) & _MASK_64;
+// _state[kSTATE_LO] = state & _MASK_32;
+// _state[kSTATE_HI] = state >> 32;
+bool Intrinsifier::Random_nextState(Assembler* assembler) {
+ const Library& math_lib = Library::Handle(Library::MathLibrary());
+ ASSERT(!math_lib.IsNull());
+ const Class& random_class =
+ Class::Handle(math_lib.LookupClassAllowPrivate(Symbols::_Random()));
+ ASSERT(!random_class.IsNull());
+ const Field& state_field = Field::ZoneHandle(
+ random_class.LookupInstanceField(Symbols::_state()));
+ ASSERT(!state_field.IsNull());
+ const Field& random_A_field = Field::ZoneHandle(
+ random_class.LookupStaticField(Symbols::_A()));
+ ASSERT(!random_A_field.IsNull());
+ ASSERT(random_A_field.is_const());
+ const Instance& a_value = Instance::Handle(random_A_field.value());
+ const int64_t a_int_value = Integer::Cast(a_value).AsInt64Value();
+ // 'a_int_value' is a mask.
+ ASSERT(Utils::IsUint(32, a_int_value));
+ int32_t a_int32_value = static_cast<int32_t>(a_int_value);
+ __ movl(EAX, Address(ESP, + 1 * kWordSize)); // Receiver.
+ __ movl(EBX, FieldAddress(EAX, state_field.Offset())); // Field '_state'.
+ // Addresses of _state[0] and _state[1].
+ Address addr_0 = FlowGraphCompiler::ElementAddressForIntIndex(
+ kTypedDataUint32ArrayCid,
+ FlowGraphCompiler::ElementSizeFor(kTypedDataUint32ArrayCid),
+ EBX,
+ 0);
+ Address addr_1 = FlowGraphCompiler::ElementAddressForIntIndex(
+ kTypedDataUint32ArrayCid,
+ FlowGraphCompiler::ElementSizeFor(kTypedDataUint32ArrayCid),
+ EBX,
+ 1);
+ __ movl(EAX, Immediate(a_int32_value));
+ // 64-bit multiply EAX * value -> EDX:EAX.
+ __ mull(addr_0);
+ __ addl(EAX, addr_1);
+ __ adcl(EDX, Immediate(0));
+ __ movl(addr_1, EDX);
+ __ movl(addr_0, EAX);
+ __ ret();
+ return true;
+}
+
+
// Identity comparison.
bool Intrinsifier::Object_equal(Assembler* assembler) {
Label is_true;
diff --git a/runtime/vm/intrinsifier_mips.cc b/runtime/vm/intrinsifier_mips.cc
index eaa50ef..d2d00bb 100644
--- a/runtime/vm/intrinsifier_mips.cc
+++ b/runtime/vm/intrinsifier_mips.cc
@@ -311,6 +311,11 @@
}
+bool Intrinsifier::Random_nextState(Assembler* assembler) {
+ return false;
+}
+
+
bool Intrinsifier::Object_equal(Assembler* assembler) {
return false;
}
diff --git a/runtime/vm/intrinsifier_x64.cc b/runtime/vm/intrinsifier_x64.cc
index c9befeb..15bec3d 100644
--- a/runtime/vm/intrinsifier_x64.cc
+++ b/runtime/vm/intrinsifier_x64.cc
@@ -8,6 +8,7 @@
#include "vm/intrinsifier.h"
#include "vm/assembler.h"
+#include "vm/flow_graph_compiler.h"
#include "vm/instructions.h"
#include "vm/object_store.h"
#include "vm/symbols.h"
@@ -1343,6 +1344,52 @@
}
+// var state = ((_A * (_state[kSTATE_LO])) + _state[kSTATE_HI]) & _MASK_64;
+// _state[kSTATE_LO] = state & _MASK_32;
+// _state[kSTATE_HI] = state >> 32;
+bool Intrinsifier::Random_nextState(Assembler* assembler) {
+ const Library& math_lib = Library::Handle(Library::MathLibrary());
+ ASSERT(!math_lib.IsNull());
+ const Class& random_class =
+ Class::Handle(math_lib.LookupClassAllowPrivate(Symbols::_Random()));
+ ASSERT(!random_class.IsNull());
+ const Field& state_field = Field::ZoneHandle(
+ random_class.LookupInstanceField(Symbols::_state()));
+ ASSERT(!state_field.IsNull());
+ const Field& random_A_field = Field::ZoneHandle(
+ random_class.LookupStaticField(Symbols::_A()));
+ ASSERT(!random_A_field.IsNull());
+ ASSERT(random_A_field.is_const());
+ const Instance& a_value = Instance::Handle(random_A_field.value());
+ const int64_t a_int_value = Integer::Cast(a_value).AsInt64Value();
+ __ movq(RAX, Address(RSP, + 1 * kWordSize)); // Receiver.
+ __ movq(RBX, FieldAddress(RAX, state_field.Offset())); // Field '_state'.
+ // Addresses of _state[0] and _state[1].
+ Address addr_0 = FlowGraphCompiler::ElementAddressForIntIndex(
+ kTypedDataUint32ArrayCid,
+ FlowGraphCompiler::ElementSizeFor(kTypedDataUint32ArrayCid),
+ RBX,
+ 0);
+ Address addr_1 = FlowGraphCompiler::ElementAddressForIntIndex(
+ kTypedDataUint32ArrayCid,
+ FlowGraphCompiler::ElementSizeFor(kTypedDataUint32ArrayCid),
+ RBX,
+ 1);
+
+ __ movq(RAX, Immediate(a_int_value));
+ __ movl(RCX, addr_0);
+ __ imulq(RCX, RAX);
+ __ movl(RDX, addr_1);
+ __ addq(RDX, RCX);
+ __ movl(addr_0, RDX);
+ __ shrq(RDX, Immediate(32));
+ __ movl(addr_1, RDX);
+ __ ret();
+ return true;
+}
+
+
+
// Identity comparison.
bool Intrinsifier::Object_equal(Assembler* assembler) {
Label is_true;
diff --git a/runtime/vm/isolate.cc b/runtime/vm/isolate.cc
index fe15ff3..6c41997 100644
--- a/runtime/vm/isolate.cc
+++ b/runtime/vm/isolate.cc
@@ -382,7 +382,6 @@
long_jump_base_(NULL),
timer_list_(),
deopt_id_(0),
- ic_data_array_(Array::null()),
mutex_(new Mutex()),
stack_limit_(0),
saved_stack_limit_(0),
@@ -650,21 +649,6 @@
}
-ICData* Isolate::GetICDataForDeoptId(intptr_t deopt_id) const {
- if (ic_data_array() == Array::null()) {
- return &ICData::ZoneHandle();
- }
- const Array& array_handle = Array::Handle(ic_data_array());
- if (deopt_id >= array_handle.Length()) {
- // For computations being added in the optimizing compiler.
- return &ICData::ZoneHandle();
- }
- ICData& ic_data_handle = ICData::ZoneHandle();
- ic_data_handle ^= array_handle.At(deopt_id);
- return &ic_data_handle;
-}
-
-
static int MostUsedFunctionFirst(const Function* const* a,
const Function* const* b) {
if ((*a)->usage_counter() > (*b)->usage_counter()) {
@@ -837,9 +821,6 @@
// Visit the top context which is stored in the isolate.
visitor->VisitPointer(reinterpret_cast<RawObject**>(&top_context_));
- // Visit the currently active IC data array.
- visitor->VisitPointer(reinterpret_cast<RawObject**>(&ic_data_array_));
-
// Visit objects in the debugger.
debugger()->VisitObjectPointers(visitor);
}
diff --git a/runtime/vm/isolate.h b/runtime/vm/isolate.h
index 407a9f8..e0059cf 100644
--- a/runtime/vm/isolate.h
+++ b/runtime/vm/isolate.h
@@ -405,10 +405,6 @@
return (deopt_id % kDeoptIdStep) == kDeoptIdAfterOffset;
}
- RawArray* ic_data_array() const { return ic_data_array_; }
- void set_ic_data_array(RawArray* value) { ic_data_array_ = value; }
- ICData* GetICDataForDeoptId(intptr_t deopt_id) const;
-
Mutex* mutex() const { return mutex_; }
Debugger* debugger() const { return debugger_; }
@@ -615,7 +611,6 @@
LongJump* long_jump_base_;
TimerList timer_list_;
intptr_t deopt_id_;
- RawArray* ic_data_array_;
Mutex* mutex_; // protects stack_limit_ and saved_stack_limit_.
uword stack_limit_;
uword saved_stack_limit_;
diff --git a/runtime/vm/object.cc b/runtime/vm/object.cc
index f620fe3..ae6e05b 100644
--- a/runtime/vm/object.cc
+++ b/runtime/vm/object.cc
@@ -943,12 +943,14 @@
cls = Class::New<Instance>(kIllegalCid);
RegisterClass(cls, Symbols::Float32x4(), lib);
+ cls.set_is_prefinalized();
pending_classes.Add(cls, Heap::kOld);
type = Type::NewNonParameterizedType(cls);
object_store->set_float32x4_type(type);
cls = Class::New<Instance>(kIllegalCid);
RegisterClass(cls, Symbols::Uint32x4(), lib);
+ cls.set_is_prefinalized();
pending_classes.Add(cls, Heap::kOld);
type = Type::NewNonParameterizedType(cls);
object_store->set_uint32x4_type(type);
@@ -976,18 +978,21 @@
cls = Class::New<Instance>(kIllegalCid);
RegisterClass(cls, Symbols::Int(), core_lib);
+ cls.set_is_prefinalized();
pending_classes.Add(cls, Heap::kOld);
type = Type::NewNonParameterizedType(cls);
object_store->set_int_type(type);
cls = Class::New<Instance>(kIllegalCid);
RegisterClass(cls, Symbols::Double(), core_lib);
+ cls.set_is_prefinalized();
pending_classes.Add(cls, Heap::kOld);
type = Type::NewNonParameterizedType(cls);
object_store->set_double_type(type);
name = Symbols::New("String");
cls = Class::New<Instance>(kIllegalCid);
+ cls.set_is_prefinalized();
RegisterClass(cls, name, core_lib);
pending_classes.Add(cls, Heap::kOld);
type = Type::NewNonParameterizedType(cls);
@@ -995,6 +1000,7 @@
cls = Class::New<Instance>(kIllegalCid);
RegisterClass(cls, Symbols::List(), core_lib);
+ cls.set_is_prefinalized();
pending_classes.Add(cls, Heap::kOld);
object_store->set_list_class(cls);
@@ -2482,7 +2488,7 @@
field ^= flds.At(i);
field_name ^= field.name();
if (String::EqualsIgnoringPrivateKey(field_name, name)) {
- return field.raw();
+ return field.raw();
}
}
// No field found.
@@ -4820,6 +4826,9 @@
const char* Field::ToCString() const {
+ if (IsNull()) {
+ return "Field::null";
+ }
const char* kF0 = is_static() ? " static" : "";
const char* kF1 = is_final() ? " final" : "";
const char* kF2 = is_const() ? " const" : "";
@@ -6054,7 +6063,8 @@
}
// Create the array of scripts and cache it in loaded_scripts_.
- StorePointer(&raw_ptr()->loaded_scripts_, Array::MakeArray(scripts));
+ const Array& scripts_array = Array::Handle(Array::MakeArray(scripts));
+ StorePointer(&raw_ptr()->loaded_scripts_, scripts_array.raw());
}
return loaded_scripts();
}
@@ -7091,7 +7101,7 @@
const char* PcDescriptors::KindAsStr(intptr_t index) const {
switch (DescriptorKind(index)) {
- case PcDescriptors::kDeopt: return "deopt ";
+ case PcDescriptors::kDeopt: return "deopt ";
case PcDescriptors::kEntryPatch: return "entry-patch ";
case PcDescriptors::kPatchCode: return "patch ";
case PcDescriptors::kLazyDeoptJump: return "lazy-deopt ";
@@ -10344,7 +10354,7 @@
if (!OS::StringToInt64(str.ToCString(), &value)) {
const Bigint& big = Bigint::Handle(Bigint::New(str, space));
ASSERT(!BigintOperations::FitsIntoSmi(big));
- ASSERT(!BigintOperations::FitsIntoMint(big));
+ ASSERT(!BigintOperations::FitsIntoInt64(big));
return big.raw();
}
return Integer::New(value, space);
@@ -10358,7 +10368,7 @@
if (!OS::StringToInt64(str.ToCString(), &value)) {
const Bigint& big = Bigint::Handle(Bigint::NewCanonical(str));
ASSERT(!BigintOperations::FitsIntoSmi(big));
- ASSERT(!BigintOperations::FitsIntoMint(big));
+ ASSERT(!BigintOperations::FitsIntoInt64(big));
return big.raw();
}
if ((value <= Smi::kMaxValue) && (value >= Smi::kMinValue)) {
@@ -10410,8 +10420,8 @@
big_value ^= raw();
if (BigintOperations::FitsIntoSmi(big_value)) {
return BigintOperations::ToSmi(big_value);
- } else if (BigintOperations::FitsIntoMint(big_value)) {
- return Mint::New(BigintOperations::ToMint(big_value));
+ } else if (BigintOperations::FitsIntoInt64(big_value)) {
+ return Mint::New(BigintOperations::ToInt64(big_value));
} else {
return big_value.raw();
}
@@ -10512,7 +10522,7 @@
const Bigint& left_big = Bigint::Handle(AsBigint());
const Bigint& right_big = Bigint::Handle(other.AsBigint());
const Bigint& result =
- Bigint::Handle(left_big.ArithmeticOp(operation, right_big));
+ Bigint::Handle(left_big.BigArithmeticOp(operation, right_big));
return Integer::Handle(result.AsValidInteger()).raw();
}
@@ -10776,7 +10786,7 @@
}
}
if (other.IsBigint()) {
- ASSERT(!BigintOperations::FitsIntoMint(Bigint::Cast(other)));
+ ASSERT(!BigintOperations::FitsIntoInt64(Bigint::Cast(other)));
if (this->IsNegative() == other.IsNegative()) {
return this->IsNegative() ? 1 : -1;
}
@@ -10918,8 +10928,8 @@
}
-RawBigint* Bigint::ArithmeticOp(Token::Kind operation,
- const Bigint& other) const {
+RawBigint* Bigint::BigArithmeticOp(Token::Kind operation,
+ const Bigint& other) const {
switch (operation) {
case Token::kADD:
return BigintOperations::Add(*this, other);
@@ -10971,7 +10981,7 @@
RawBigint* Bigint::New(const String& str, Heap::Space space) {
const Bigint& result = Bigint::Handle(
BigintOperations::NewFromCString(str.ToCString(), space));
- ASSERT(!BigintOperations::FitsIntoMint(result));
+ ASSERT(!BigintOperations::FitsIntoInt64(result));
return result.raw();
}
@@ -10979,7 +10989,7 @@
RawBigint* Bigint::NewCanonical(const String& str) {
const Bigint& value = Bigint::Handle(
BigintOperations::NewFromCString(str.ToCString(), Heap::kOld));
- ASSERT(!BigintOperations::FitsIntoMint(value));
+ ASSERT(!BigintOperations::FitsIntoInt64(value));
const Class& cls =
Class::Handle(Isolate::Current()->object_store()->bigint_class());
const Array& constants = Array::Handle(cls.constants());
@@ -11012,17 +11022,17 @@
int64_t Bigint::AsInt64Value() const {
- if (!BigintOperations::FitsIntoMint(*this)) {
+ if (!BigintOperations::FitsIntoInt64(*this)) {
UNREACHABLE();
}
- return BigintOperations::ToMint(*this);
+ return BigintOperations::ToInt64(*this);
}
// For positive values: Smi < Mint < Bigint.
int Bigint::CompareWith(const Integer& other) const {
ASSERT(!FitsIntoSmi(*this));
- ASSERT(!BigintOperations::FitsIntoMint(*this));
+ ASSERT(!BigintOperations::FitsIntoInt64(*this));
if (other.IsBigint()) {
return BigintOperations::Compare(*this, Bigint::Cast(other));
}
diff --git a/runtime/vm/object.h b/runtime/vm/object.h
index b5406ff..755262e 100644
--- a/runtime/vm/object.h
+++ b/runtime/vm/object.h
@@ -216,7 +216,10 @@
ASSERT(!IsNull());
raw()->SetCanonical();
}
-
+ intptr_t GetClassId() const {
+ return !raw()->IsHeapObject() ?
+ static_cast<intptr_t>(kSmiCid) : raw()->GetClassId();
+ }
inline RawClass* clazz() const;
static intptr_t tags_offset() { return OFFSET_OF(RawObject, tags_); }
@@ -4096,12 +4099,12 @@
return RoundedAllocationSize(sizeof(RawBigint) + (len * kBytesPerElement));
}
- RawBigint* ArithmeticOp(Token::Kind operation, const Bigint& other) const;
-
protected:
// Only Integer::NewXXX is allowed to call Bigint::NewXXX directly.
friend class Integer;
+ RawBigint* BigArithmeticOp(Token::Kind operation, const Bigint& other) const;
+
static RawBigint* New(const String& str, Heap::Space space = Heap::kNew);
// Returns a canonical Bigint object allocated in the old gen space.
diff --git a/runtime/vm/parser.cc b/runtime/vm/parser.cc
index 33db8c2..2628ce3 100644
--- a/runtime/vm/parser.cc
+++ b/runtime/vm/parser.cc
@@ -3250,7 +3250,8 @@
} else {
// Not patching a class, but it has been found. This must be one of the
// pre-registered classes from object.cc or a duplicate definition.
- if (cls.functions() != Object::empty_array().raw()) {
+ if (!(cls.is_prefinalized() ||
+ RawObject::IsTypedDataViewClassId(cls.id()))) {
ErrorMsg(classname_pos, "class '%s' is already defined",
class_name.ToCString());
}
diff --git a/runtime/vm/raw_object_snapshot.cc b/runtime/vm/raw_object_snapshot.cc
index 60a22ec..30df9e1 100644
--- a/runtime/vm/raw_object_snapshot.cc
+++ b/runtime/vm/raw_object_snapshot.cc
@@ -138,8 +138,9 @@
intptr_t num_flds = (unresolved_class.raw()->to() -
unresolved_class.raw()->from());
for (intptr_t i = 0; i <= num_flds; i++) {
+ (*reader->ObjectHandle()) = reader->ReadObjectRef();
unresolved_class.StorePointer((unresolved_class.raw()->from() + i),
- reader->ReadObjectRef());
+ reader->ObjectHandle()->raw());
}
return unresolved_class.raw();
}
@@ -201,7 +202,8 @@
// allocations may happen.
intptr_t num_flds = (type.raw()->to() - type.raw()->from());
for (intptr_t i = 0; i <= num_flds; i++) {
- type.StorePointer((type.raw()->from() + i), reader->ReadObjectRef());
+ (*reader->ObjectHandle()) = reader->ReadObjectRef();
+ type.StorePointer((type.raw()->from() + i), reader->ObjectHandle()->raw());
}
// If object needs to be a canonical object, Canonicalize it.
@@ -315,8 +317,9 @@
intptr_t num_flds = (type_parameter.raw()->to() -
type_parameter.raw()->from());
for (intptr_t i = 0; i <= num_flds; i++) {
+ (*reader->ObjectHandle()) = reader->ReadObjectRef();
type_parameter.StorePointer((type_parameter.raw()->from() + i),
- reader->ReadObjectRef());
+ reader->ObjectHandle()->raw());
}
return type_parameter.raw();
@@ -386,8 +389,9 @@
intptr_t num_flds = (bounded_type.raw()->to() -
bounded_type.raw()->from());
for (intptr_t i = 0; i <= num_flds; i++) {
+ (*reader->ObjectHandle()) = reader->ReadObjectRef();
bounded_type.StorePointer((bounded_type.raw()->from() + i),
- reader->ReadObjectRef());
+ reader->ObjectHandle()->raw());
}
bounded_type.set_is_being_checked(false);
@@ -536,9 +540,10 @@
intptr_t num_flds = (instantiated_type_arguments.raw()->to() -
instantiated_type_arguments.raw()->from());
for (intptr_t i = 0; i <= num_flds; i++) {
+ (*reader->ObjectHandle()) = reader->ReadObjectRef();
instantiated_type_arguments.StorePointer(
(instantiated_type_arguments.raw()->from() + i),
- reader->ReadObjectRef());
+ reader->ObjectHandle()->raw());
}
return instantiated_type_arguments.raw();
}
@@ -1352,7 +1357,9 @@
// allocations may happen.
intptr_t num_flds = (context.raw()->to(num_vars) - context.raw()->from());
for (intptr_t i = 0; i <= num_flds; i++) {
- context.StorePointer((context.raw()->from() + i), reader->ReadObjectRef());
+ (*reader->ObjectHandle()) = reader->ReadObjectRef();
+ context.StorePointer((context.raw()->from() + i),
+ reader->ObjectHandle()->raw());
}
return context.raw();
@@ -1481,8 +1488,9 @@
// allocations may happen.
intptr_t num_flds = (api_error.raw()->to() - api_error.raw()->from());
for (intptr_t i = 0; i <= num_flds; i++) {
+ (*reader->ObjectHandle()) = reader->ReadObjectRef();
api_error.StorePointer((api_error.raw()->from() + i),
- reader->ReadObjectRef());
+ reader->ObjectHandle()->raw());
}
return api_error.raw();
@@ -1527,8 +1535,9 @@
intptr_t num_flds =
(language_error.raw()->to() - language_error.raw()->from());
for (intptr_t i = 0; i <= num_flds; i++) {
+ (*reader->ObjectHandle()) = reader->ReadObjectRef();
language_error.StorePointer((language_error.raw()->from() + i),
- reader->ReadObjectRef());
+ reader->ObjectHandle()->raw());
}
return language_error.raw();
diff --git a/runtime/vm/simulator_arm.cc b/runtime/vm/simulator_arm.cc
index 59d6d29..4e161c6 100644
--- a/runtime/vm/simulator_arm.cc
+++ b/runtime/vm/simulator_arm.cc
@@ -18,6 +18,7 @@
#include "vm/constants_arm.h"
#include "vm/disassembler.h"
#include "vm/native_arguments.h"
+#include "vm/stack_frame.h"
#include "vm/thread.h"
namespace dart {
@@ -113,6 +114,13 @@
bool GetFValue(char* desc, float* value);
bool GetDValue(char* desc, double* value);
+ void PrintDartFrame(uword pc, uword fp, uword sp,
+ const Function& function,
+ intptr_t token_pos,
+ bool is_optimized,
+ bool is_inlined);
+ void PrintBacktrace();
+
// Set or delete a breakpoint. Returns true if successful.
bool SetBreakpoint(Instr* breakpc);
bool DeleteBreakpoint(Instr* breakpc);
@@ -254,6 +262,79 @@
}
+void SimulatorDebugger::PrintDartFrame(uword pc, uword fp, uword sp,
+ const Function& function,
+ intptr_t token_pos,
+ bool is_optimized,
+ bool is_inlined) {
+ const Script& script = Script::Handle(function.script());
+ const String& func_name = String::Handle(function.QualifiedUserVisibleName());
+ const String& url = String::Handle(script.url());
+ intptr_t line = -1;
+ intptr_t column = -1;
+ if (token_pos >= 0) {
+ script.GetTokenLocation(token_pos, &line, &column);
+ }
+ OS::Print("pc=0x%"Px" fp=0x%"Px" sp=0x%"Px" %s%s (%s:%"Pd":%"Pd")\n",
+ pc, fp, sp,
+ is_optimized ? (is_inlined ? "inlined " : "optimized ") : "",
+ func_name.ToCString(),
+ url.ToCString(),
+ line, column);
+}
+
+
+void SimulatorDebugger::PrintBacktrace() {
+ StackFrameIterator frames(sim_->get_register(FP),
+ sim_->get_register(SP),
+ sim_->get_pc(),
+ StackFrameIterator::kDontValidateFrames);
+ StackFrame* frame = frames.NextFrame();
+ ASSERT(frame != NULL);
+ Function& function = Function::Handle();
+ Function& inlined_function = Function::Handle();
+ Code& code = Code::Handle();
+ Code& unoptimized_code = Code::Handle();
+ while (frame != NULL) {
+ if (frame->IsDartFrame()) {
+ code = frame->LookupDartCode();
+ function = code.function();
+ if (code.is_optimized()) {
+ // For optimized frames, extract all the inlined functions if any
+ // into the stack trace.
+ InlinedFunctionsIterator it(frame);
+ while (!it.Done()) {
+ // Print each inlined frame with its pc in the corresponding
+ // unoptimized frame.
+ inlined_function = it.function();
+ unoptimized_code = it.code();
+ uword unoptimized_pc = it.pc();
+ it.Advance();
+ if (!it.Done()) {
+ PrintDartFrame(unoptimized_pc, frame->fp(), frame->sp(),
+ inlined_function,
+ unoptimized_code.GetTokenIndexOfPC(unoptimized_pc),
+ true, true);
+ }
+ }
+ // Print the optimized inlining frame below.
+ }
+ PrintDartFrame(frame->pc(), frame->fp(), frame->sp(),
+ function,
+ code.GetTokenIndexOfPC(frame->pc()),
+ code.is_optimized(), false);
+ } else {
+ OS::Print("pc=0x%"Px" fp=0x%"Px" sp=0x%"Px" %s frame\n",
+ frame->pc(), frame->fp(), frame->sp(),
+ frame->IsEntryFrame() ? "entry" :
+ frame->IsExitFrame() ? "exit" :
+ frame->IsStubFrame() ? "stub" : "invalid");
+ }
+ frame = frames.NextFrame();
+ }
+}
+
+
bool SimulatorDebugger::SetBreakpoint(Instr* breakpc) {
// Check if a breakpoint can be set. If not return without any side-effects.
if (sim_->break_pc_ != NULL) {
@@ -350,6 +431,8 @@
"pd/printdouble <dreg or *addr> -- print double value\n"
"po/printobject <*reg or *addr> -- print object\n"
"si/stepi -- single step an instruction\n"
+ "trace -- toggle execution tracing mode\n"
+ "bt -- print backtrace\n"
"unstop -- if current pc is a stop instr make it a nop\n"
"q/quit -- Quit the debugger and exit the program\n");
} else if ((strcmp(cmd, "quit") == 0) || (strcmp(cmd, "q") == 0)) {
@@ -481,6 +564,11 @@
} else {
OS::Print("Not at debugger stop.\n");
}
+ } else if (strcmp(cmd, "trace") == 0) {
+ FLAG_trace_sim = !FLAG_trace_sim;
+ OS::Print("execution tracing %s\n", FLAG_trace_sim ? "on" : "off");
+ } else if (strcmp(cmd, "bt") == 0) {
+ PrintBacktrace();
} else {
OS::Print("Unknown command: %s\n", cmd);
}
diff --git a/runtime/vm/stack_frame.cc b/runtime/vm/stack_frame.cc
index b45d133..163e653 100644
--- a/runtime/vm/stack_frame.cc
+++ b/runtime/vm/stack_frame.cc
@@ -215,6 +215,7 @@
uword exit_marker = *reinterpret_cast<uword*>(exit_address);
frames_.fp_ = exit_marker;
frames_.sp_ = 0;
+ frames_.pc_ = 0;
}
@@ -223,29 +224,52 @@
SetupLastExitFrameData(); // Setup data for last exit frame.
}
+
StackFrameIterator::StackFrameIterator(uword last_fp, bool validate)
: validate_(validate), entry_(), exit_(), current_frame_(NULL) {
frames_.fp_ = last_fp;
+ frames_.sp_ = 0;
+ frames_.pc_ = 0;
+}
+
+
+StackFrameIterator::StackFrameIterator(uword fp, uword sp, uword pc,
+ bool validate)
+ : validate_(validate), entry_(), exit_(), current_frame_(NULL) {
+ frames_.fp_ = fp;
+ frames_.sp_ = sp;
+ frames_.pc_ = pc;
}
StackFrame* StackFrameIterator::NextFrame() {
// When we are at the start of iteration after having created an
- // iterator object current_frame_ will be NULL as we haven't seen
- // any frames yet. At this point if NextFrame is called it tries
+ // iterator object, current_frame_ will be NULL as we haven't seen
+ // any frames yet (unless we start iterating in the simulator from a given
+ // triplet of fp, sp, and pc). At this point, if NextFrame is called, it tries
// to set up the next exit frame by reading the top_exit_frame_info
- // from the isolate. If we do not have any dart invocations yet
+ // from the isolate. If we do not have any dart invocations yet,
// top_exit_frame_info will be 0 and so we would return NULL.
// current_frame_ will also be NULL, when we are at the end of having
- // iterated through all the frames. if NextFrame is called at this
- // point we will try and set up the next exit frame but since we are
- // at the end of the iteration fp_ will be 0 and we would return NULL.
+ // iterated through all the frames. If NextFrame is called at this
+ // point, we will try and set up the next exit frame, but since we are
+ // at the end of the iteration, fp_ will be 0 and we would return NULL.
if (current_frame_ == NULL) {
if (!HasNextFrame()) {
return NULL;
}
- current_frame_ = NextExitFrame();
+ if (frames_.pc_ == 0) {
+ // Iteration starts from an exit frame given by its fp.
+ current_frame_ = NextExitFrame();
+ } else if (*(reinterpret_cast<uword*>(
+ frames_.fp_ + (kSavedCallerFpSlotFromFp * kWordSize))) == 0) {
+ // Iteration starts from an entry frame given by its fp, sp, and pc.
+ current_frame_ = NextEntryFrame();
+ } else {
+ // Iteration starts from a Dart or stub frame given by its fp, sp, and pc.
+ current_frame_ = frames_.NextFrame(validate_);
+ }
return current_frame_;
}
ASSERT((validate_ == kDontValidateFrames) || current_frame_->IsValid());
@@ -276,8 +300,10 @@
frame = &stack_frame_;
frame->sp_ = sp_;
frame->fp_ = fp_;
+ frame->pc_ = pc_;
sp_ = frame->GetCallerSp();
fp_ = frame->GetCallerFp();
+ pc_ = frame->GetCallerPc();
ASSERT((validate == kDontValidateFrames) || frame->IsValid());
return frame;
}
@@ -286,8 +312,10 @@
ExitFrame* StackFrameIterator::NextExitFrame() {
exit_.sp_ = frames_.sp_;
exit_.fp_ = frames_.fp_;
+ exit_.pc_ = frames_.pc_;
frames_.sp_ = exit_.GetCallerSp();
frames_.fp_ = exit_.GetCallerFp();
+ frames_.pc_ = exit_.GetCallerPc();
ASSERT(exit_.IsValid());
return &exit_;
}
@@ -297,6 +325,7 @@
ASSERT(!frames_.HasNext());
entry_.sp_ = frames_.sp_;
entry_.fp_ = frames_.fp_;
+ entry_.pc_ = frames_.pc_;
SetupNextExitFrameData(); // Setup data for next exit frame in chain.
ASSERT(entry_.IsValid());
return &entry_;
@@ -317,7 +346,7 @@
intptr_t deopt_reason = kDeoptUnknown;
deopt_info_ = code_.GetDeoptInfoAtPc(frame->pc(), &deopt_reason);
if (deopt_info_.IsNull()) {
- // This is the case when a call without deopt info in optimzed code
+ // This is the case when a call without deopt info in optimized code
// throws an exception. (e.g. in the parameter copying prologue).
// In that case there won't be any inlined frames.
function_ = code_.function();
diff --git a/runtime/vm/stack_frame.h b/runtime/vm/stack_frame.h
index 10b63c5..2b206fa 100644
--- a/runtime/vm/stack_frame.h
+++ b/runtime/vm/stack_frame.h
@@ -36,9 +36,7 @@
// Accessors to get the pc, sp and fp of a frame.
uword sp() const { return sp_; }
uword fp() const { return fp_; }
- uword pc() const {
- return *reinterpret_cast<uword*>(sp_ + (kSavedPcSlotFromSp * kWordSize));
- }
+ uword pc() const { return pc_; }
// The pool pointer is not implemented on all architectures.
static int SavedCallerPpSlotFromFp() {
@@ -79,7 +77,7 @@
protected:
- StackFrame() : fp_(0), sp_(0) { }
+ StackFrame() : fp_(0), sp_(0), pc_(0) { }
// Name of the frame, used for generic frame printing functionality.
virtual const char* GetName() const { return IsStubFrame()? "stub" : "dart"; }
@@ -94,9 +92,14 @@
return *(reinterpret_cast<uword*>(
fp() + (kSavedCallerFpSlotFromFp * kWordSize)));
}
+ uword GetCallerPc() const {
+ return *(reinterpret_cast<uword*>(
+ fp() + (kSavedCallerPcSlotFromFp * kWordSize)));
+ }
uword fp_;
uword sp_;
+ uword pc_;
// The iterators FrameSetIterator and StackFrameIterator set the private
// fields fp_ and sp_ when they return the respective frame objects.
@@ -154,16 +157,20 @@
};
-// Iterator for iterating over all frames from the last ExitFrame to the
-// first EntryFrame.
class StackFrameIterator : public ValueObject {
public:
static const bool kValidateFrames = true;
static const bool kDontValidateFrames = false;
+ // Iterators for iterating over all frames from the last ExitFrame to the
+ // first EntryFrame.
explicit StackFrameIterator(bool validate);
StackFrameIterator(uword last_fp, bool validate);
+ // Iterator for iterating over all frames from the current frame (given by its
+ // fp, sp, and pc) to the first EntryFrame.
+ StackFrameIterator(uword fp, uword sp, uword pc, bool validate);
+
// Checks if a next frame exists.
bool HasNextFrame() const { return frames_.fp_ != 0; }
@@ -189,10 +196,11 @@
StackFrame* NextFrame(bool validate);
private:
- FrameSetIterator() : fp_(0), sp_(0), stack_frame_() { }
+ FrameSetIterator() : fp_(0), sp_(0), pc_(0), stack_frame_() { }
uword fp_;
uword sp_;
+ uword pc_;
StackFrame stack_frame_; // Singleton frame returned by NextFrame().
friend class StackFrameIterator;
diff --git a/runtime/vm/symbols.h b/runtime/vm/symbols.h
index 2c85c1c..efe97a0 100644
--- a/runtime/vm/symbols.h
+++ b/runtime/vm/symbols.h
@@ -257,6 +257,9 @@
V(DartTypedData, "dart:typed_data") \
V(DartUri, "dart:uri") \
V(DartUtf, "dart:utf") \
+ V(_Random, "_Random") \
+ V(_state, "_state") \
+ V(_A, "_A") \
// Contains a list of frequently used strings in a canonicalized form. This
diff --git a/sdk/lib/_internal/compiler/implementation/apiimpl.dart b/sdk/lib/_internal/compiler/implementation/apiimpl.dart
index 2c94493..69d3cfa 100644
--- a/sdk/lib/_internal/compiler/implementation/apiimpl.dart
+++ b/sdk/lib/_internal/compiler/implementation/apiimpl.dart
@@ -38,6 +38,8 @@
outputProvider: outputProvider,
enableTypeAssertions: hasOption(options, '--enable-checked-mode'),
enableUserAssertions: hasOption(options, '--enable-checked-mode'),
+ trustTypeAnnotations:
+ hasOption(options, '--trust-type-annotations'),
enableMinification: hasOption(options, '--minify'),
enableNativeLiveTypeAnalysis:
!hasOption(options, '--disable-native-live-type-analysis'),
diff --git a/sdk/lib/_internal/compiler/implementation/closure.dart b/sdk/lib/_internal/compiler/implementation/closure.dart
index fff0b37..b1d62ca 100644
--- a/sdk/lib/_internal/compiler/implementation/closure.dart
+++ b/sdk/lib/_internal/compiler/implementation/closure.dart
@@ -67,7 +67,9 @@
// move these classes to elements/modelx.dart or see if we can find a
// more general solution.
class ClosureFieldElement extends ElementX {
- ClosureFieldElement(SourceString name, ClassElement enclosing)
+ ClosureFieldElement(SourceString name,
+ this.variableElement,
+ ClassElement enclosing)
: super(name, ElementKind.FIELD, enclosing);
bool isInstanceMember() => true;
@@ -77,9 +79,16 @@
bool hasFixedBackendName() => true;
String fixedBackendName() => name.slowToString();
- DartType computeType(Compiler compiler) => compiler.types.dynamicType;
+ DartType computeType(Compiler compiler) {
+ return variableElement.computeType(compiler);
+ }
String toString() => "ClosureFieldElement($name)";
+
+ /**
+ * The source variable this element refers to.
+ */
+ final Element variableElement;
}
// TODO(ahe): These classes continuously cause problems. We need to
@@ -114,10 +123,12 @@
Token position() => node.getBeginToken();
+ Node parseNode(DiagnosticListener listener) => node;
+
/**
* The most outer method this closure is declared into.
*/
- Element methodElement;
+ final Element methodElement;
}
// TODO(ahe): These classes continuously cause problems. We need to
@@ -126,6 +137,24 @@
class BoxElement extends ElementX {
BoxElement(SourceString name, Element enclosingElement)
: super(name, ElementKind.VARIABLE, enclosingElement);
+
+ DartType computeType(Compiler compiler) => compiler.types.dynamicType;
+}
+
+// TODO(ngeoffray, ahe): These classes continuously cause problems. We need to
+// move these classes to elements/modelx.dart or see if we can find a
+// more general solution.
+class BoxFieldElement extends ElementX {
+ BoxFieldElement(SourceString name,
+ this.variableElement,
+ BoxElement enclosingBox)
+ : super(name, ElementKind.FIELD, enclosingBox);
+
+ DartType computeType(Compiler compiler) {
+ return variableElement.computeType(compiler);
+ }
+
+ final Element variableElement;
}
// TODO(ahe): These classes continuously cause problems. We need to
@@ -137,6 +166,8 @@
bool isAssignable() => false;
+ DartType computeType(Compiler compiler) => compiler.types.dynamicType;
+
// Since there is no declaration corresponding to 'this', use the position of
// the enclosing method.
Token position() => enclosingElement.position();
@@ -150,6 +181,8 @@
CheckVariableElement(SourceString name, this.parameter, Element enclosing)
: super(name, ElementKind.VARIABLE, enclosing);
+ DartType computeType(Compiler compiler) => compiler.types.dynamicType;
+
// Since there is no declaration for the synthetic 'check' variable, use
// parameter.
Token position() => parameter.position();
@@ -226,25 +259,25 @@
return copy != null && !copy.isMember();
}
- void forEachCapturedVariable(void f(Element element)) {
- freeVariableMapping.forEach((variable, _) {
+ void forEachCapturedVariable(void f(Element local, Element field)) {
+ freeVariableMapping.forEach((variable, copy) {
if (variable is BoxElement) return;
- f(variable);
+ f(variable, copy);
});
}
- void forEachBoxedVariable(void f(Element element)) {
+ void forEachBoxedVariable(void f(Element local, Element field)) {
freeVariableMapping.forEach((variable, copy) {
if (!isVariableBoxed(variable)) return;
- f(variable);
+ f(variable, copy);
});
}
- void forEachNonBoxedCapturedVariable(void f(Element element)) {
+ void forEachNonBoxedCapturedVariable(void f(Element local, Element field)) {
freeVariableMapping.forEach((variable, copy) {
if (variable is BoxElement) return;
if (isVariableBoxed(variable)) return;
- f(variable);
+ f(variable, copy);
});
}
}
@@ -342,8 +375,9 @@
assert(closureElement != null ||
(fieldCaptures.isEmpty && boxes.isEmpty));
void addElement(Element element, SourceString name) {
- Element fieldElement = new ClosureFieldElement(name, closureElement);
- closureElement.addBackendMember(fieldElement);
+ Element fieldElement = new ClosureFieldElement(
+ name, element, closureElement);
+ closureElement.addMember(fieldElement, compiler);
data.capturedFieldMapping[fieldElement] = element;
freeVariableMapping[element] = fieldElement;
}
@@ -568,7 +602,7 @@
namer.getClosureVariableName(new SourceString(elementName),
boxedFieldCounter++);
// TODO(kasperl): Should this be a FieldElement instead?
- Element boxed = new ElementX(boxedName, ElementKind.FIELD, box);
+ Element boxed = new BoxFieldElement(boxedName, element, box);
// No need to rename the fields of a box, so we give them a native name
// right now.
boxed.setFixedBackendName(boxedName.slowToString());
@@ -658,7 +692,7 @@
new FunctionElementX.from(Compiler.CALL_OPERATOR_NAME,
element,
globalizedElement);
- globalizedElement.addBackendMember(callElement);
+ globalizedElement.addMember(callElement, compiler);
// The nested function's 'this' is the same as the one for the outer
// function. It could be [null] if we are inside a static method.
Element thisElement = closureData.thisElement;
diff --git a/sdk/lib/_internal/compiler/implementation/compile_time_constants.dart b/sdk/lib/_internal/compiler/implementation/compile_time_constants.dart
index dc99d27..47b66c2 100644
--- a/sdk/lib/_internal/compiler/implementation/compile_time_constants.dart
+++ b/sdk/lib/_internal/compiler/implementation/compile_time_constants.dart
@@ -884,8 +884,7 @@
}
jsNewArguments.add(fieldValue);
},
- includeBackendMembers: true,
- includeSuperMembers: true);
+ includeSuperAndInjectedMembers: true);
return jsNewArguments;
}
}
diff --git a/sdk/lib/_internal/compiler/implementation/compiler.dart b/sdk/lib/_internal/compiler/implementation/compiler.dart
index c2de002..a292e28 100644
--- a/sdk/lib/_internal/compiler/implementation/compiler.dart
+++ b/sdk/lib/_internal/compiler/implementation/compiler.dart
@@ -137,7 +137,8 @@
Enqueuer enqueuer,
TreeElements elements) {}
void registerStringInterpolation(TreeElements elements) {}
- void registerCatchStatement(TreeElements elements) {}
+ void registerCatchStatement(Enqueuer enqueuer,
+ TreeElements elements) {}
void registerWrapException(TreeElements elements) {}
void registerThrowExpression(TreeElements elements) {}
void registerLazyField(TreeElements elements) {}
@@ -251,6 +252,7 @@
final bool enableMinification;
final bool enableTypeAssertions;
final bool enableUserAssertions;
+ final bool trustTypeAnnotations;
final bool enableConcreteTypeInference;
/**
* The maximum size of a concrete type before it widens to dynamic during
@@ -440,6 +442,7 @@
Compiler({this.tracer: const Tracer(),
this.enableTypeAssertions: false,
this.enableUserAssertions: false,
+ this.trustTypeAnnotations: false,
this.enableConcreteTypeInference: false,
this.maxConcreteTypeSize: 5,
this.enableMinification: false,
@@ -1024,7 +1027,6 @@
if (message is TypeWarning) {
// TODO(ahe): Don't supress these warning when the type checker
// is more complete.
- if (identical(message.message.kind, MessageKind.NOT_ASSIGNABLE)) return;
if (identical(message.message.kind, MessageKind.MISSING_RETURN)) return;
if (identical(message.message.kind, MessageKind.MAYBE_MISSING_RETURN)) {
return;
diff --git a/sdk/lib/_internal/compiler/implementation/dart2js.dart b/sdk/lib/_internal/compiler/implementation/dart2js.dart
index 1afb82b..20856b7 100644
--- a/sdk/lib/_internal/compiler/implementation/dart2js.dart
+++ b/sdk/lib/_internal/compiler/implementation/dart2js.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.
-library dart2js;
+library dart2js.cmdline;
import 'dart:async';
import 'dart:collection' show Queue, LinkedHashMap;
@@ -212,6 +212,8 @@
(_) => passThrough('--enable-checked-mode')),
new OptionHandler('--enable-concrete-type-inference',
(_) => passThrough('--enable-concrete-type-inference')),
+ new OptionHandler('--trust-type-annotations',
+ (_) => passThrough('--trust-type-annotations')),
new OptionHandler(r'--help|/\?|/h', (_) => wantHelp = true),
new OptionHandler('--package-root=.+|-p.+', setPackageRoot),
new OptionHandler('--disallow-unsafe-eval', passThrough),
diff --git a/sdk/lib/_internal/compiler/implementation/dart_types.dart b/sdk/lib/_internal/compiler/implementation/dart_types.dart
index ecee2ba..bcec921 100644
--- a/sdk/lib/_internal/compiler/implementation/dart_types.dart
+++ b/sdk/lib/_internal/compiler/implementation/dart_types.dart
@@ -341,6 +341,8 @@
return visitor.visitMalformedType(this, argument);
}
+ bool operator ==(other) => identical(this, other);
+
String toString() {
var sb = new StringBuffer();
if (typeArguments != null) {
@@ -446,8 +448,9 @@
}
bool operator ==(other) {
- if (!identical(element, other.element)) return false;
- return typeArguments == other.typeArguments;
+ if (other is !GenericType) return false;
+ return identical(element, other.element)
+ && typeArguments == other.typeArguments;
}
bool get isRaw => typeArguments.isEmpty || identical(this, element.rawType);
@@ -521,7 +524,9 @@
ClassElement classElement = element;
InterfaceType receiver = this;
InterfaceType declarer = receiver;
- Element member = classElement.lookupLocalMember(name);
+ // TODO(johnniwinther): Lookup and callers should handle private members and
+ // injected members.
+ Element member = classElement.implementation.lookupLocalMember(name);
if (member != null) {
return createMember(receiver, declarer, member);
}
@@ -533,7 +538,7 @@
if (supertype.element.isMixinApplication) continue;
declarer = supertype;
ClassElement lookupTarget = declarer.element;
- member = lookupTarget.lookupLocalMember(name);
+ member = lookupTarget.implementation.lookupLocalMember(name);
if (member != null) {
return createMember(receiver, declarer, member);
}
diff --git a/sdk/lib/_internal/compiler/implementation/elements/elements.dart b/sdk/lib/_internal/compiler/implementation/elements/elements.dart
index cecab14..c0bc01e4 100644
--- a/sdk/lib/_internal/compiler/implementation/elements/elements.dart
+++ b/sdk/lib/_internal/compiler/implementation/elements/elements.dart
@@ -198,6 +198,7 @@
bool isTypedef();
bool isTypeVariable();
bool isField();
+ bool isFieldParameter();
bool isAbstractField();
bool isGetter();
bool isSetter();
@@ -488,15 +489,13 @@
/// A `compareTo` function that places [Element]s in a consistent order based
/// on the source code order.
static int compareByPosition(Element a, Element b) {
- CompilationUnitElement unitA = a.getCompilationUnit();
- CompilationUnitElement unitB = b.getCompilationUnit();
- if (!identical(unitA, unitB)) {
- int r = unitA.script.uri.path.compareTo(unitB.script.uri.path);
- if (r != 0) return r;
- }
+ int r = a.getLibrary().compareTo(b.getLibrary());
+ if (r != 0) return r;
+ r = a.getCompilationUnit().compareTo(b.getCompilationUnit());
+ if (r != 0) return r;
Token positionA = a.position();
Token positionB = b.position();
- int r = positionA.charOffset.compareTo(positionB.charOffset);
+ r = positionA.charOffset.compareTo(positionB.charOffset);
if (r != 0) return r;
r = a.name.slowToString().compareTo(b.name.slowToString());
if (r != 0) return r;
@@ -548,6 +547,16 @@
}
return false;
}
+
+ static bool isUnusedLabel(LabeledStatement node, TreeElements elements) {
+ Node body = node.statement;
+ TargetElement element = elements[body];
+ // Labeled statements with no element on the body have no breaks.
+ // A different target statement only happens if the body is itself
+ // a break or continue for a different target. In that case, this
+ // label is also always unused.
+ return element == null || element.statement != body;
+ }
}
abstract class ErroneousElement extends Element implements FunctionElement {
@@ -578,6 +587,8 @@
void addMember(Element element, DiagnosticListener listener);
void setPartOf(PartOf tag, DiagnosticListener listener);
bool get hasMembers;
+
+ int compareTo(CompilationUnitElement other);
}
abstract class LibraryElement extends Element implements ScopeContainerElement {
@@ -639,6 +650,8 @@
bool hasLibraryName();
String getLibraryOrScriptName();
+
+ int compareTo(LibraryElement other);
}
abstract class PrefixElement extends Element {
@@ -837,11 +850,10 @@
void forEachMember(void f(ClassElement enclosingClass, Element member),
{includeBackendMembers: false,
- includeSuperMembers: false});
+ includeSuperAndInjectedMembers: false});
void forEachInstanceField(void f(ClassElement enclosingClass, Element field),
- {includeBackendMembers: false,
- includeSuperMembers: false});
+ {includeSuperAndInjectedMembers: false});
void forEachBackendMember(void f(Element member));
}
diff --git a/sdk/lib/_internal/compiler/implementation/elements/modelx.dart b/sdk/lib/_internal/compiler/implementation/elements/modelx.dart
index 0cb0a4d..d8f90d4 100644
--- a/sdk/lib/_internal/compiler/implementation/elements/modelx.dart
+++ b/sdk/lib/_internal/compiler/implementation/elements/modelx.dart
@@ -84,6 +84,7 @@
bool isTypedef() => identical(kind, ElementKind.TYPEDEF);
bool isTypeVariable() => identical(kind, ElementKind.TYPE_VARIABLE);
bool isField() => identical(kind, ElementKind.FIELD);
+ bool isFieldParameter() => identical(kind, ElementKind.FIELD_PARAMETER);
bool isAbstractField() => identical(kind, ElementKind.ABSTRACT_FIELD);
bool isGetter() => identical(kind, ElementKind.GETTER);
bool isSetter() => identical(kind, ElementKind.SETTER);
@@ -525,6 +526,11 @@
}
bool get hasMembers => !localMembers.isEmpty;
+
+ int compareTo(CompilationUnitElement other) {
+ if (this == other) return 0;
+ return '${script.uri}'.compareTo('${other.script.uri}');
+ }
}
class LibraryElementX extends ElementX implements LibraryElement {
@@ -770,6 +776,11 @@
return 'library(${getLibraryOrScriptName()})';
}
}
+
+ int compareTo(LibraryElement other) {
+ if (this == other) return 0;
+ return getLibraryOrScriptName().compareTo(other.getLibraryOrScriptName());
+ }
}
class PrefixElementX extends ElementX implements PrefixElement {
@@ -1498,6 +1509,8 @@
void setDefaultConstructor(FunctionElement constructor, Compiler compiler);
void addBackendMember(Element member) {
+ // TODO(ngeoffray): Deprecate this method.
+ assert(member.isGenerativeConstructorBody());
backendMembers = backendMembers.prepend(member);
}
@@ -1590,6 +1603,11 @@
current != null;
current = current.superclass) {
Element member = current.lookupLocalMember(name);
+ if (member == null && current.isPatched) {
+ // Doing lookups on selectors is done after resolution, so it
+ // is safe to look in the patch class.
+ member = current.patch.lookupLocalMember(name);
+ }
if (member == null) continue;
// Private members from a different library are not visible.
if (isPrivate && !identical(library, member.getLibrary())) continue;
@@ -1715,7 +1733,7 @@
* Runs through all members of this class.
*
* The enclosing class is passed to the callback. This is useful when
- * [includeSuperMembers] is [:true:].
+ * [includeSuperAndInjectedMembers] is [:true:].
*
* When called on an implementation element both the members in the origin
* and patch class are included.
@@ -1723,8 +1741,8 @@
// TODO(johnniwinther): Clean up lookup to get rid of the include predicates.
void forEachMember(void f(ClassElement enclosingClass, Element member),
{includeBackendMembers: false,
- includeSuperMembers: false}) {
- bool includeInjectedMembers = isPatch;
+ includeSuperAndInjectedMembers: false}) {
+ bool includeInjectedMembers = includeSuperAndInjectedMembers || isPatch;
Set<ClassElement> seen = new Set<ClassElement>();
ClassElement classElement = declaration;
do {
@@ -1746,7 +1764,9 @@
});
}
}
- classElement = includeSuperMembers ? classElement.superclass : null;
+ classElement = includeSuperAndInjectedMembers
+ ? classElement.superclass
+ : null;
} while(classElement != null);
}
@@ -1754,18 +1774,13 @@
* Runs through all instance-field members of this class.
*
* The enclosing class is passed to the callback. This is useful when
- * [includeSuperMembers] is [:true:].
- *
- * When [includeBackendMembers] and [includeSuperMembers] are both [:true:]
- * then the fields are visited in the same order as they need to be given
- * to the JavaScript constructor.
+ * [includeSuperAndInjectedMembers] is [:true:].
*
* When called on the implementation element both the fields declared in the
* origin and in the patch are included.
*/
void forEachInstanceField(void f(ClassElement enclosingClass, Element field),
- {includeBackendMembers: false,
- includeSuperMembers: false}) {
+ {includeSuperAndInjectedMembers: false}) {
// Filters so that [f] is only invoked with instance fields.
void fieldFilter(ClassElement enclosingClass, Element member) {
if (member.isInstanceMember() && member.kind == ElementKind.FIELD) {
@@ -1774,8 +1789,7 @@
}
forEachMember(fieldFilter,
- includeBackendMembers: includeBackendMembers,
- includeSuperMembers: includeSuperMembers);
+ includeSuperAndInjectedMembers: includeSuperAndInjectedMembers);
}
void forEachBackendMember(void f(Element member)) {
diff --git a/sdk/lib/_internal/compiler/implementation/js_backend/backend.dart b/sdk/lib/_internal/compiler/implementation/js_backend/backend.dart
index 79ad151..b4bfbdb 100644
--- a/sdk/lib/_internal/compiler/implementation/js_backend/backend.dart
+++ b/sdk/lib/_internal/compiler/implementation/js_backend/backend.dart
@@ -646,6 +646,7 @@
ClassElement jsDoubleClass;
ClassElement jsNullClass;
ClassElement jsBoolClass;
+ ClassElement jsUnknownClass;
ClassElement jsIndexableClass;
ClassElement jsMutableIndexableClass;
@@ -862,7 +863,7 @@
if (uses == null) return null;
Set<ClassElement> result = null;
for (MixinApplicationElement use in uses) {
- Iterable<ClassElement> subclasses = compiler.world.subclasses[use];
+ Iterable<ClassElement> subclasses = compiler.world.subclassesOf(use);
if (subclasses != null) {
for (ClassElement subclass in subclasses) {
if (subclass.isNative()) {
@@ -921,7 +922,10 @@
jsFixedArrayClass =
compiler.findInterceptor(const SourceString('JSFixedArray')),
jsExtendableArrayClass =
- compiler.findInterceptor(const SourceString('JSExtendableArray'))];
+ compiler.findInterceptor(const SourceString('JSExtendableArray')),
+ jsUnknownClass =
+ compiler.findInterceptor(const SourceString('JSUnknown')),
+ ];
jsIndexableClass =
compiler.findInterceptor(const SourceString('JSIndexable'));
@@ -1012,7 +1016,7 @@
classesMixedIntoNativeClasses.add(mixinApplication.mixin);
}
},
- includeSuperMembers: true);
+ includeSuperAndInjectedMembers: true);
}
}
@@ -1028,7 +1032,7 @@
member.name, () => new Set<Element>());
set.add(member);
},
- includeSuperMembers: true);
+ includeSuperAndInjectedMembers: true);
}
enqueuer.registerInstantiatedClass(cls, elements);
}
@@ -1124,6 +1128,8 @@
addInterceptors(jsIntClass, enqueuer, elements);
addInterceptors(jsDoubleClass, enqueuer, elements);
addInterceptors(jsNumberClass, enqueuer, elements);
+ } else if (cls == jsUnknownClass) {
+ addInterceptors(jsUnknownClass, enqueuer, elements);
} else if (cls.isNative()) {
addInterceptorsForNativeClassMembers(cls, enqueuer);
}
@@ -1134,7 +1140,7 @@
if (!member.isInstanceMember() || !member.isField()) return;
DartType type = member.computeType(compiler);
enqueuer.registerIsCheck(type, elements);
- }, includeSuperMembers: true);
+ }, includeSuperAndInjectedMembers: true);
}
}
@@ -1177,8 +1183,11 @@
enqueueInResolution(getStringInterpolationHelper(), elements);
}
- void registerCatchStatement(TreeElements elements) {
+ void registerCatchStatement(Enqueuer enqueuer, TreeElements elements) {
enqueueInResolution(getExceptionUnwrapper(), elements);
+ if (jsUnknownClass != null) {
+ enqueuer.registerInstantiatedClass(jsUnknownClass, elements);
+ }
}
void registerWrapException(TreeElements elements) {
@@ -1680,7 +1689,8 @@
? const SourceString("stringSuperTypeCast")
: const SourceString('stringSuperTypeCheck');
}
- } else if (element == compiler.listClass || element == jsArrayClass) {
+ } else if ((element == compiler.listClass || element == jsArrayClass) &&
+ type.isRaw) {
if (nativeCheckOnly) return null;
return typeCast
? const SourceString("listTypeCast")
@@ -1704,15 +1714,18 @@
? const SourceString("interceptedTypeCast")
: const SourceString('interceptedTypeCheck');
} else {
- if (typeCast) {
- return const SourceString("propertyTypeCast");
- }
if (type.kind == TypeKind.INTERFACE && !type.isRaw) {
- return const SourceString('assertSubtype');
+ return typeCast
+ ? const SourceString('subtypeCast')
+ : const SourceString('assertSubtype');
} else if (type.kind == TypeKind.TYPE_VARIABLE) {
- return const SourceString('assertSubtypeOfRuntimeType');
+ return typeCast
+ ? const SourceString('subtypeOfRuntimeTypeCast')
+ : const SourceString('assertSubtypeOfRuntimeType');
} else {
- return const SourceString('propertyTypeCheck');
+ return typeCast
+ ? const SourceString('propertyTypeCast')
+ : const SourceString('propertyTypeCheck');
}
}
}
diff --git a/sdk/lib/_internal/compiler/implementation/js_backend/constant_emitter.dart b/sdk/lib/_internal/compiler/implementation/js_backend/constant_emitter.dart
index 9273ad7..2b4d152 100644
--- a/sdk/lib/_internal/compiler/implementation/js_backend/constant_emitter.dart
+++ b/sdk/lib/_internal/compiler/implementation/js_backend/constant_emitter.dart
@@ -269,8 +269,7 @@
}
emittedArgumentCount++;
},
- includeBackendMembers: true,
- includeSuperMembers: true);
+ includeSuperAndInjectedMembers: true);
if ((constant.protoValue == null && emittedArgumentCount != 3) ||
(constant.protoValue != null && emittedArgumentCount != 4)) {
diff --git a/sdk/lib/_internal/compiler/implementation/js_backend/emitter.dart b/sdk/lib/_internal/compiler/implementation/js_backend/emitter.dart
index a1f1c9a..e269d41 100644
--- a/sdk/lib/_internal/compiler/implementation/js_backend/emitter.dart
+++ b/sdk/lib/_internal/compiler/implementation/js_backend/emitter.dart
@@ -1197,8 +1197,7 @@
classElement.implementation.forEachMember(
visitMember,
- includeBackendMembers: true,
- includeSuperMembers: false);
+ includeBackendMembers: true);
if (identical(classElement, compiler.objectClass)
&& compiler.enabledNoSuchMethod) {
@@ -1349,8 +1348,7 @@
// superclasses for non-instantiated classes.
classElement.implementation.forEachInstanceField(
visitField,
- includeBackendMembers: true,
- includeSuperMembers: isInstantiated);
+ includeSuperAndInjectedMembers: isInstantiated);
}
void generateGetter(Element member, String fieldName, String accessorName,
@@ -1800,8 +1798,15 @@
.where(isStaticFunction)
.toSet();
+ LibraryElement previousLibrary = null;
for (Element element in Elements.sortedByPosition(elements)) {
CodeBuffer buffer = bufferForElement(element, eagerBuffer);
+ LibraryElement library = element.getLibrary();
+ if (library != previousLibrary) {
+ previousLibrary = library;
+ addComment(
+ 'Library: ${library.getLibraryOrScriptName()}', buffer);
+ }
jsAst.Expression code = backend.generatedCode[element];
emitStaticFunction(buffer, namer.getName(element), code);
jsAst.Expression bailoutCode = backend.generatedBailoutCode[element];
@@ -1811,6 +1816,9 @@
}
}
+ if (!pendingElementsWithBailouts.isEmpty) {
+ addComment('pendingElementsWithBailouts', eagerBuffer);
+ }
// Is it possible the primary function was inlined but the bailout was not?
for (Element element in
Elements.sortedByPosition(pendingElementsWithBailouts)) {
@@ -2601,6 +2609,14 @@
['receiver'])));
} else {
+ ClassElement jsUnknown = backend.jsUnknownClass;
+ if (compiler.codegenWorld.instantiatedClasses.contains(jsUnknown)) {
+ block.statements.add(
+ js.if_(js('!(receiver instanceof #)',
+ js(namer.isolateAccess(compiler.objectClass))),
+ buildReturnInterceptor(jsUnknown)));
+ }
+
block.statements.add(js.return_(js('receiver')));
}
@@ -2958,7 +2974,14 @@
// Might create boundClosures.
if (!regularClasses.isEmpty) {
addComment('Classes', mainBuffer);
+ LibraryElement previousLibrary = null;
for (ClassElement element in regularClasses) {
+ LibraryElement library = element.getLibrary();
+ if (library != previousLibrary) {
+ previousLibrary = library;
+ addComment(
+ 'Library: ${library.getLibraryOrScriptName()}', mainBuffer);
+ }
generateClass(element, mainBuffer);
}
}
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 0c02e6e..21f07e2 100644
--- a/sdk/lib/_internal/compiler/implementation/js_backend/runtime_types.dart
+++ b/sdk/lib/_internal/compiler/implementation/js_backend/runtime_types.dart
@@ -115,7 +115,7 @@
classesNeedingRti.add(cls);
// TODO(ngeoffray): This should use subclasses, not subtypes.
- Set<ClassElement> classes = compiler.world.subtypes[cls];
+ Set<ClassElement> classes = compiler.world.subtypesOf(cls);
if (classes != null) {
classes.forEach((ClassElement sub) {
potentiallyAddForRti(sub);
diff --git a/sdk/lib/_internal/compiler/implementation/lib/interceptors.dart b/sdk/lib/_internal/compiler/implementation/lib/interceptors.dart
index d5dccf6..35de8a8 100644
--- a/sdk/lib/_internal/compiler/implementation/lib/interceptors.dart
+++ b/sdk/lib/_internal/compiler/implementation/lib/interceptors.dart
@@ -139,6 +139,9 @@
}
record = lookupDispatchRecord(object);
+ if (record == null) {
+ return const JSUnknown();
+ }
setDispatchProperty(JS('', 'Object.getPrototypeOf(#)', object), record);
return getNativeInterceptor(object);
}
@@ -335,6 +338,15 @@
Type get runtimeType => Null;
}
+class JSUnknown extends Interceptor {
+ const JSUnknown();
+
+ String toString() => JS('String', 'String(#)', this);
+
+ int get hashCode => 0;
+
+ Type get runtimeType => null;
+}
/**
* The supertype for JSString and JSArray. Used by the backend as to
diff --git a/sdk/lib/_internal/compiler/implementation/lib/js_helper.dart b/sdk/lib/_internal/compiler/implementation/lib/js_helper.dart
index f5350d1..56e7221 100644
--- a/sdk/lib/_internal/compiler/implementation/lib/js_helper.dart
+++ b/sdk/lib/_internal/compiler/implementation/lib/js_helper.dart
@@ -19,7 +19,8 @@
makeDispatchRecord,
setDispatchProperty,
Interceptor,
- JSMutableIndexable;
+ JSMutableIndexable,
+ JSUnknown;
import "dart:_collection-dev" as _symbol_dev;
part 'constant_map.dart';
@@ -294,6 +295,13 @@
/** [: r"$".codeUnitAt(0) :] */
static const int DOLLAR_CHAR_VALUE = 36;
+ /// Creates a string containing the complete type for the class [className]
+ /// with the given type arguments.
+ static String formatType(String className, List typeArguments) {
+ return '$className${joinArguments(typeArguments, 0)}';
+ }
+
+ /// Returns the type of [object] as a string (including type arguments).
static String objectTypeName(Object object) {
String name = constructorNameFallback(object);
if (name == 'Object') {
@@ -306,8 +314,10 @@
}
// TODO(kasperl): If the namer gave us a fresh global name, we may
// want to remove the numeric suffix that makes it unique too.
- if (identical(name.codeUnitAt(0), DOLLAR_CHAR_VALUE)) name = name.substring(1);
- return name;
+ if (identical(name.codeUnitAt(0), DOLLAR_CHAR_VALUE)) {
+ name = name.substring(1);
+ }
+ return formatType(name, getRuntimeTypeInfo(object));
}
static String objectToString(Object object) {
@@ -757,8 +767,13 @@
unwrapException(ex) {
// Note that we are checking if the object has the property. If it
// has, it could be set to null if the thrown value is null.
+ if (ex == null) return null;
+ if (JS('bool', 'typeof # !== "object"', ex)) return ex;
+
if (JS('bool', r'"dartException" in #', ex)) {
return JS('', r'#.dartException', ex);
+ } else if (!JS('bool', r'"message" in #', ex)) {
+ return ex;
}
// Grab hold of the exception message. This field is available on
@@ -795,7 +810,7 @@
message.endsWith('is null or undefined') ||
message.endsWith('of undefined') ||
message.endsWith('of null')) {
- return new NoSuchMethodError(null, '<unknown>', [], {});
+ return new NoSuchMethodError(null, message, [], {});
} else if (contains(message, ' has no method ') ||
contains(message, ' is not a function') ||
(ieErrorCode == 438 && ieFacilityNumber == 10)) {
@@ -805,7 +820,7 @@
// Object doesn't support property or method 'foo' which sets the error
// code 438 in IE.
// TODO(kasperl): Compute the right name if possible.
- return new NoSuchMethodError('', '<unknown>', [], {});
+ return new NoSuchMethodError('', message, [], {});
}
}
@@ -846,7 +861,13 @@
* exception.
*/
StackTrace getTraceFromException(exception) {
- return new _StackTrace(JS("var", r"#.stack", exception));
+ if (exception == null) return null;
+ if (JS('bool', 'typeof # !== "object"', exception)) return null;
+ if (JS('bool', r'"stack" in #', exception)) {
+ return new _StackTrace(JS("var", r"#.stack", exception));
+ } else {
+ return null;
+ }
}
class _StackTrace implements StackTrace {
diff --git a/sdk/lib/_internal/compiler/implementation/lib/js_rti.dart b/sdk/lib/_internal/compiler/implementation/lib/js_rti.dart
index 2085dc4..21be9af 100644
--- a/sdk/lib/_internal/compiler/implementation/lib/js_rti.dart
+++ b/sdk/lib/_internal/compiler/implementation/lib/js_rti.dart
@@ -134,14 +134,27 @@
return checkArguments(substitution, arguments, checks);
}
+String computeTypeName(String isField, List arguments) {
+ // Shorten the field name to the class name and append the textual
+ // representation of the type arguments.
+ int prefixLength = JS_OPERATOR_IS_PREFIX().length;
+ return Primitives.formatType(isField.substring(prefixLength, isField.length),
+ arguments);
+}
+
+Object subtypeCast(Object object, String isField, List checks, String asField) {
+ if (!checkSubtype(object, isField, checks, asField)) {
+ String actualType = Primitives.objectTypeName(object);
+ String typeName = computeTypeName(isField, checks);
+ throw new CastErrorImplementation(object, typeName);
+ }
+ return object;
+}
+
Object assertSubtype(Object object, String isField, List checks,
String asField) {
if (!checkSubtype(object, isField, checks, asField)) {
- // Shorten the field name to the class name and append the textual
- // representation of the type arguments.
- int prefixLength = JS_OPERATOR_IS_PREFIX().length;
- String typeName = '${isField.substring(prefixLength, isField.length)}'
- '${joinArguments(checks, 0)}';
+ String typeName = computeTypeName(isField, checks);
throw new TypeErrorImplementation(object, typeName);
}
return object;
@@ -212,6 +225,14 @@
return isSubtype(type, t);
}
+Object subtypeOfRuntimeTypeCast(Object object, var type) {
+ if (!checkSubtypeOfRuntimeType(object, type)) {
+ String actualType = Primitives.objectTypeName(object);
+ throw new CastErrorImplementation(actualType, runtimeTypeToString(type));
+ }
+ return object;
+}
+
Object assertSubtypeOfRuntimeType(Object object, var type) {
if (!checkSubtypeOfRuntimeType(object, type)) {
throw new TypeErrorImplementation(object, runtimeTypeToString(type));
diff --git a/sdk/lib/_internal/compiler/implementation/lib/native_helper.dart b/sdk/lib/_internal/compiler/implementation/lib/native_helper.dart
index 1fa69ec..b7a1f44 100644
--- a/sdk/lib/_internal/compiler/implementation/lib/native_helper.dart
+++ b/sdk/lib/_internal/compiler/implementation/lib/native_helper.dart
@@ -79,9 +79,11 @@
if (object == null) return 'Null';
var constructor = JS('var', "#.constructor", object);
if (identical(JS('String', "typeof(#)", constructor), 'function')) {
+ var name = JS('var', r'#.builtin$cls', constructor);
+ if (name != null) return name;
// The constructor isn't null or undefined at this point. Try
// to grab hold of its name.
- var name = JS('var', '#.name', constructor);
+ name = JS('var', '#.name', constructor);
// If the name is a non-empty string, we use that as the type
// name of this object. On Firefox, we often get 'Object' as
// the constructor name even for more specialized objects so
@@ -269,6 +271,7 @@
lookupInterceptor(var hasOwnPropertyFunction, String tag) {
var map = interceptorsByTag;
+ if (map == null) return null;
return callHasOwnProperty(hasOwnPropertyFunction, map, tag)
? propertyGet(map, tag)
: null;
@@ -288,11 +291,17 @@
}
}
if (interceptor == null) {
- // TODO(sra): Think about the error case.
- interceptor = JS('', '{__what: "interceptor not found", __tag: #}', tag);
+ // This object is not known to Dart. There could be several
+ // reasons for that, including (but not limited to):
+ // * A bug in native code (hopefully this is caught during development).
+ // * An unknown DOM object encountered.
+ // * JavaScript code running in an unexpected context. For
+ // example, on node.js.
+ return null;
}
- var isLeaf = JS('', '#[#]', leafTags, tag);
- if (true == isLeaf) {
+ var isLeaf =
+ (leafTags != null) && JS('bool', '(#[#]) === true', leafTags, tag);
+ if (isLeaf) {
return makeDispatchRecord(interceptor, false, null);
} else {
var proto = JS('', 'Object.getPrototypeOf(#)', obj);
diff --git a/sdk/lib/_internal/compiler/implementation/mirrors/dart2js_mirror.dart b/sdk/lib/_internal/compiler/implementation/mirrors/dart2js_mirror.dart
index e196afa..9be802d 100644
--- a/sdk/lib/_internal/compiler/implementation/mirrors/dart2js_mirror.dart
+++ b/sdk/lib/_internal/compiler/implementation/mirrors/dart2js_mirror.dart
@@ -1587,7 +1587,7 @@
String fieldName = field.name.slowToString();
_fieldMapCache.putIfAbsent(fieldName, () => _constant.fields[index]);
index++;
- }, includeBackendMembers: true, includeSuperMembers: true);
+ }, includeSuperAndInjectedMembers: true);
}
}
return _fieldMapCache;
diff --git a/sdk/lib/_internal/compiler/implementation/resolution/members.dart b/sdk/lib/_internal/compiler/implementation/resolution/members.dart
index c6a7a9a..b4fe9d9 100644
--- a/sdk/lib/_internal/compiler/implementation/resolution/members.dart
+++ b/sdk/lib/_internal/compiler/implementation/resolution/members.dart
@@ -876,7 +876,7 @@
// TODO(johnniwinther): Store the mapping in the resolution enqueuer.
element.mapping = mapping;
return compiler.withCurrentElement(element, () {
- measure(() {
+ return measure(() {
Typedef node =
compiler.parser.measure(() => element.parseNode(compiler));
TypedefResolverVisitor visitor =
@@ -2201,6 +2201,10 @@
compiler.backend.registerClassUsingVariableExpression(cls);
compiler.backend.registerTypeVariableExpression(mapping);
} else if (target.impliesType() && !sendIsMemberAccess) {
+ // Set the type of the node to [Type] to mark this send as a
+ // type literal.
+ mapping.setType(node, compiler.typeClass.computeType(compiler));
+ world.registerInstantiatedClass(compiler.typeClass, mapping);
compiler.backend.registerTypeLiteral(mapping);
}
}
@@ -2556,8 +2560,7 @@
(ClassElement enclosingClass, Element member) {
world.addToWorkList(member);
},
- includeBackendMembers: false,
- includeSuperMembers: true);
+ includeSuperAndInjectedMembers: true);
if (isSymbolConstructor) {
if (node.isConst()) {
@@ -2968,7 +2971,7 @@
}
visitCatchBlock(CatchBlock node) {
- compiler.backend.registerCatchStatement(mapping);
+ compiler.backend.registerCatchStatement(world, mapping);
// Check that if catch part is present, then
// it has one or two formal parameters.
if (node.formals != null) {
@@ -3740,7 +3743,19 @@
requiredParameterCount = parametersBuilder.length;
parameters = parametersBuilder.toLink();
}
- DartType returnType = compiler.resolveReturnType(element, returnNode);
+ DartType returnType;
+ if (element.isFactoryConstructor()) {
+ returnType = element.getEnclosingClass().computeType(compiler);
+ // Because there is no type annotation for the return type of
+ // this element, we explicitly add one.
+ if (compiler.enableTypeAssertions) {
+ compiler.enqueuer.resolution.registerIsCheck(
+ returnType, new TreeElementMapping(element));
+ }
+ } else {
+ returnType = compiler.resolveReturnType(element, returnNode);
+ }
+
if (element.isSetter() && (requiredParameterCount != 1 ||
visitor.optionalParameterCount != 0)) {
// If there are no formal parameters, we already reported an error above.
diff --git a/sdk/lib/_internal/compiler/implementation/ssa/builder.dart b/sdk/lib/_internal/compiler/implementation/ssa/builder.dart
index 1722f9f..ae43bed 100644
--- a/sdk/lib/_internal/compiler/implementation/ssa/builder.dart
+++ b/sdk/lib/_internal/compiler/implementation/ssa/builder.dart
@@ -103,10 +103,7 @@
}
HGraph compileConstructor(SsaBuilder builder, CodegenWorkItem work) {
- // The body of the constructor will be generated in a separate function.
- final ClassElement classElement = work.element.getEnclosingClass();
- return builder.buildFactory(classElement.implementation,
- work.element.implementation);
+ return builder.buildFactory(work.element);
}
}
@@ -279,8 +276,7 @@
builder.graph.thisInstruction = thisInstruction;
builder.graph.entry.addAtEntry(thisInstruction);
updateLocal(closureData.closureElement, thisInstruction);
- } else if (element.isInstanceMember()
- || element.isGenerativeConstructor()) {
+ } else if (element.isInstanceMember()) {
// Once closures have been mapped to classes their instance members might
// not have any thisElement if the closure was created inside a static
// context.
@@ -376,7 +372,7 @@
Element redirect = redirectionMapping[element];
HInstruction receiver = readLocal(closureData.closureElement);
HInstruction fieldGet = new HFieldGet(redirect, receiver);
- fieldGet.instructionType = builder.getTypeOfCapturedVariable(element);
+ fieldGet.instructionType = builder.getTypeOfCapturedVariable(redirect);
builder.add(fieldGet);
return fieldGet;
} else if (isBoxed(element)) {
@@ -389,7 +385,7 @@
assert(redirect.enclosingElement.isVariable());
HInstruction box = readLocal(redirect.enclosingElement);
HInstruction lookup = new HFieldGet(redirect, box);
- lookup.instructionType = builder.getTypeOfCapturedVariable(element);
+ lookup.instructionType = builder.getTypeOfCapturedVariable(redirect);
builder.add(lookup);
return lookup;
} else {
@@ -1014,6 +1010,7 @@
new Map<Element, HType>();
HType getTypeOfCapturedVariable(Element element) {
+ assert(element.isField());
return cachedTypesOfCapturedVariables.putIfAbsent(element, () {
return new HType.inferredTypeForElement(element, compiler);
});
@@ -1116,6 +1113,7 @@
}
HParameterValue addParameter(Element element) {
+ assert(inliningStack.isEmpty);
HParameterValue result = new HParameterValue(element);
if (lastAddedParameter == null) {
graph.entry.addBefore(graph.entry.first, result);
@@ -1178,7 +1176,7 @@
// may have an impact on the state of the current method.
InliningState state = new InliningState(
function, returnElement, returnType, elements, stack, localsHandler);
- LocalsHandler newLocalsHandler = new LocalsHandler.from(localsHandler);
+ LocalsHandler newLocalsHandler = new LocalsHandler(this);
newLocalsHandler.closureData =
compiler.closureToClassMapper.computeClosureToClassMapping(
function, function.parseNode(compiler), elements);
@@ -1272,7 +1270,6 @@
if (element is !PartialFunctionElement) return false;
// TODO(ngeoffray): try to inline generative constructors. They
// don't have any body, which make it more difficult.
- if (element.isGenerativeConstructor()) return false;
if (inliningStack.length > MAX_INLINING_DEPTH) return false;
// Don't inline recursive calls. We use the same elements for the inlined
// functions and would thus clobber our local variables.
@@ -1319,18 +1316,20 @@
}
assert(canBeInlined);
- InliningState state = enterInlinedMethod(
- function, selector, argumentsNodes, providedArguments, currentNode);
- // Add an explicit null check on the receiver. We use [element]
- // to get the same name in the NoSuchMethodError message as if we had
- // called it.
+ // Add an explicit null check on the receiver before doing the
+ // inlining. We use [element] to get the same name in the NoSuchMethodError
+ // message as if we had called it.
if (element.isInstanceMember()
&& (selector.mask == null || selector.mask.isNullable)) {
addWithPosition(
new HFieldGet(element, providedArguments[0]), currentNode);
}
+ InliningState state = enterInlinedMethod(
+ function, selector, argumentsNodes, providedArguments, currentNode);
inlinedFrom(element, () {
- functionExpression.body.accept(this);
+ element.isGenerativeConstructor()
+ ? buildFactory(element)
+ : functionExpression.body.accept(this);
});
leaveInlinedMethod(state);
return true;
@@ -1436,11 +1435,6 @@
ClosureClassMap newClosureData =
compiler.closureToClassMapper.computeClosureToClassMapping(
constructor, node, elements);
- // The [:this:] element now refers to the one in the new closure
- // data, that is the [:this:] of the super constructor. We
- // update the element to refer to the current [:this:].
- localsHandler.updateLocal(newClosureData.thisElement,
- localsHandler.readThis());
localsHandler.closureData = newClosureData;
params.orderedForEachParameter((Element parameterElement) {
@@ -1564,9 +1558,7 @@
}
fieldValues[member] = value;
});
- },
- includeBackendMembers: true,
- includeSuperMembers: false);
+ });
}
@@ -1578,21 +1570,20 @@
* to, starting from the current constructor.
* - Call the the constructor bodies, starting from the constructor(s) in the
* super class(es).
- *
- * Invariant: Both [classElement] and [functionElement] must be
- * implementation elements.
*/
- HGraph buildFactory(ClassElement classElement,
- FunctionElement functionElement) {
- assert(invariant(classElement, classElement.isImplementation));
- assert(invariant(functionElement, functionElement.isImplementation));
+ HGraph buildFactory(FunctionElement functionElement) {
+ functionElement = functionElement.implementation;
+ ClassElement classElement =
+ functionElement.getEnclosingClass().implementation;
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
// arguments as if they were positional.
- // The initializer list could contain closures.
- openFunction(functionElement, function);
+ if (inliningStack.isEmpty) {
+ // The initializer list could contain closures.
+ openFunction(functionElement, function);
+ }
Map<Element, HInstruction> fieldValues = new Map<Element, HInstruction>();
@@ -1624,8 +1615,7 @@
constructorArguments.add(potentiallyCheckType(
fieldValues[member], member.computeType(compiler)));
},
- includeBackendMembers: true,
- includeSuperMembers: true);
+ includeSuperAndInjectedMembers: true);
InterfaceType type = classElement.computeType(compiler);
HType ssaType = new HType.nonNullExact(type, compiler);
@@ -1696,24 +1686,18 @@
bodyCallInputs.add(localsHandler.readLocal(scopeData.boxElement));
}
- // TODO(ahe): The constructor name is statically resolved. See
- // SsaCodeGenerator.visitInvokeDynamicMethod. Is there a cleaner
- // way to do this?
- SourceString name =
- new SourceString(backend.namer.getName(body.declaration));
- // TODO(kasperl): This seems fishy. We shouldn't be inventing all
- // these selectors. Maybe the resolver can do more of the work
- // for us here?
- LibraryElement library = body.getLibrary();
- Selector selector = new Selector.call(
- name, library, bodyCallInputs.length - 1);
- HInvokeDynamic invoke =
- new HInvokeDynamicMethod(selector, bodyCallInputs);
- invoke.element = body;
+ HInvokeConstructorBody invoke =
+ new HInvokeConstructorBody(body, bodyCallInputs);
+ invoke.sideEffects = compiler.world.getSideEffectsOfElement(constructor);
add(invoke);
}
- closeAndGotoExit(new HReturn(newObject));
- return closeFunction();
+ if (inliningStack.isEmpty) {
+ closeAndGotoExit(new HReturn(newObject));
+ return closeFunction();
+ } else {
+ localsHandler.updateLocal(returnElement, newObject);
+ return null;
+ }
}
void addParameterCheckInstruction(Element element) {
@@ -1830,14 +1814,12 @@
}
}
- HInstruction buildTypeConversion(Compiler compiler, HInstruction original,
- DartType type, int kind) {
+ HInstruction buildTypeConversion(HInstruction original,
+ DartType type,
+ int kind) {
if (type == null) return original;
if (type.kind == TypeKind.INTERFACE && !type.isMalformed && !type.isRaw) {
HType subtype = new HType.subtype(type, compiler);
- if (type.isRaw) {
- return new HTypeConversion(type, kind, subtype, original);
- }
HInstruction representations = buildTypeArgumentRepresentations(type);
add(representations);
return new HTypeConversion.withTypeRepresentation(type, kind, subtype,
@@ -1855,8 +1837,7 @@
HInstruction potentiallyCheckType(HInstruction original, DartType type,
{ int kind: HTypeConversion.CHECKED_MODE_CHECK }) {
if (!compiler.enableTypeAssertions) return original;
- HInstruction other =
- buildTypeConversion(compiler, original, type, kind);
+ HInstruction other = buildTypeConversion(original, type, kind);
if (other != original) add(other);
return other;
}
@@ -2487,10 +2468,9 @@
// TODO(ahe): This should be registered in codegen, not here.
compiler.enqueuer.codegen.registerInstantiatedClass(
closureClassElement, work.resolutionTree);
- assert(!closureClassElement.hasLocalScopeMembers);
List<HInstruction> capturedVariables = <HInstruction>[];
- closureClassElement.forEachBackendMember((Element member) {
+ closureClassElement.forEachMember((_, Element member) {
// The backendMembers also contains the call method(s). We are only
// interested in the fields.
if (member.isField()) {
@@ -2802,8 +2782,8 @@
Node argument = node.arguments.head;
TypeAnnotation typeAnnotation = argument.asTypeAnnotation();
DartType type = elements.getType(typeAnnotation);
- HInstruction converted = expression.convertType(
- compiler, type, HTypeConversion.CAST_TYPE_CHECK);
+ HInstruction converted = buildTypeConversion(
+ expression, type, HTypeConversion.CAST_TYPE_CHECK);
if (converted != expression) add(converted);
stack.add(converted);
} else {
@@ -2847,7 +2827,7 @@
return new HIs(type, <HInstruction>[expression, call],
HIs.VARIABLE_CHECK);
} else if (RuntimeTypes.hasTypeArguments(type)) {
- Element element = type.element;
+ ClassElement element = type.element;
Element helper = backend.getCheckSubtype();
HInstruction representations =
buildTypeArgumentRepresentations(type);
@@ -2855,10 +2835,9 @@
String operator =
backend.namer.operatorIs(backend.getImplementationClass(element));
HInstruction isFieldName = addConstantString(node, operator);
- // TODO(karlklose): use [:null:] for [asField] if [element] does not
- // have a subclass.
- HInstruction asFieldName =
- addConstantString(node, backend.namer.substitutionName(element));
+ HInstruction asFieldName = compiler.world.hasAnySubtype(element)
+ ? addConstantString(node, backend.namer.substitutionName(element))
+ : graph.addConstantNull(constantSystem);
List<HInstruction> inputs = <HInstruction>[expression,
isFieldName,
representations,
@@ -4274,21 +4253,14 @@
visitLabeledStatement(LabeledStatement node) {
Statement body = node.statement;
- if (body is Loop || body is SwitchStatement) {
+ if (body is Loop
+ || body is SwitchStatement
+ || Elements.isUnusedLabel(node, elements)) {
// Loops and switches handle their own labels.
visit(body);
return;
}
- // Non-loop statements can only be break targets, not continue targets.
TargetElement targetElement = elements[body];
- if (targetElement == null || !identical(targetElement.statement, body)) {
- // Labeled statements with no element on the body have no breaks.
- // A different target statement only happens if the body is itself
- // a break or continue for a different target. In that case, this
- // label is also always unused.
- visit(body);
- return;
- }
LocalsHandler beforeLocals = new LocalsHandler.from(localsHandler);
assert(targetElement.isBreakTarget);
JumpHandler handler = new JumpHandler(this, targetElement);
@@ -5083,6 +5055,7 @@
static bool canBeInlined(FunctionExpression functionExpression,
TreeElements elements) {
InlineWeeder weeder = new InlineWeeder(elements);
+ weeder.visit(functionExpression.initializers);
weeder.visit(functionExpression.body);
if (weeder.tooDifficult) return false;
return true;
@@ -5098,7 +5071,7 @@
}
void visit(Node node) {
- node.accept(this);
+ if (node != null) node.accept(this);
}
void visitNode(Node node) {
diff --git a/sdk/lib/_internal/compiler/implementation/ssa/codegen.dart b/sdk/lib/_internal/compiler/implementation/ssa/codegen.dart
index 48d4466..d420f27 100644
--- a/sdk/lib/_internal/compiler/implementation/ssa/codegen.dart
+++ b/sdk/lib/_internal/compiler/implementation/ssa/codegen.dart
@@ -741,6 +741,10 @@
js.Catch catchPart = null;
js.Block finallyPart = null;
if (info.catchBlock != null) {
+ if (backend.jsUnknownClass != null) {
+ world.registerInstantiatedClass(
+ backend.jsUnknownClass, work.resolutionTree);
+ }
HLocalValue exception = info.catchVariable;
String name = variableNames.getName(exception);
js.VariableDeclaration decl = new js.VariableDeclaration(name);
@@ -1483,32 +1487,26 @@
List<js.Expression> arguments = visitArguments(node.inputs);
Element target = node.element;
- if (target != null) {
- // Avoid adding the generative constructor name to the list of
- // seen selectors.
- if (target.isGenerativeConstructorBody()) {
- methodName = name.slowToString();
- } else if (!node.isInterceptedCall) {
- if (target == backend.jsArrayAdd) {
- methodName = 'push';
- } else if (target == backend.jsArrayRemoveLast) {
- methodName = 'pop';
- } else if (target == backend.jsStringSplit) {
- methodName = 'split';
- // Split returns a List, so we make sure the backend knows the
- // list class is instantiated.
- world.registerInstantiatedClass(
- compiler.listClass, work.resolutionTree);
- } else if (target == backend.jsStringConcat) {
- push(new js.Binary('+', object, arguments[0]), node);
- return;
- } else if (target.isNative() && target.isFunction()
- && !node.isInterceptedCall) {
- // A direct (i.e. non-interceptor) native call is the result of
- // optimization. The optimization ensures any type checks or
- // conversions have been satisified.
- methodName = target.fixedBackendName();
- }
+ if (target != null && !node.isInterceptedCall) {
+ if (target == backend.jsArrayAdd) {
+ methodName = 'push';
+ } else if (target == backend.jsArrayRemoveLast) {
+ methodName = 'pop';
+ } else if (target == backend.jsStringSplit) {
+ methodName = 'split';
+ // Split returns a List, so we make sure the backend knows the
+ // list class is instantiated.
+ world.registerInstantiatedClass(
+ compiler.listClass, work.resolutionTree);
+ } else if (target == backend.jsStringConcat) {
+ push(new js.Binary('+', object, arguments[0]), node);
+ return;
+ } else if (target.isNative() && target.isFunction()
+ && !node.isInterceptedCall) {
+ // A direct (i.e. non-interceptor) native call is the result of
+ // optimization. The optimization ensures any type checks or
+ // conversions have been satisified.
+ methodName = target.fixedBackendName();
}
}
@@ -1519,6 +1517,14 @@
push(jsPropertyCall(object, methodName, arguments), node);
}
+ void visitInvokeConstructorBody(HInvokeConstructorBody node) {
+ use(node.inputs[0]);
+ js.Expression object = pop();
+ String methodName = backend.namer.getName(node.element);
+ List<js.Expression> arguments = visitArguments(node.inputs);
+ push(jsPropertyCall(object, methodName, arguments), node);
+ }
+
void visitOneShotInterceptor(HOneShotInterceptor node) {
List<js.Expression> arguments = visitArguments(node.inputs);
var isolate = new js.VariableUse(backend.namer.CURRENT_ISOLATE);
diff --git a/sdk/lib/_internal/compiler/implementation/ssa/codegen_helpers.dart b/sdk/lib/_internal/compiler/implementation/ssa/codegen_helpers.dart
index ce3c0e3..c29f3e8 100644
--- a/sdk/lib/_internal/compiler/implementation/ssa/codegen_helpers.dart
+++ b/sdk/lib/_internal/compiler/implementation/ssa/codegen_helpers.dart
@@ -357,11 +357,17 @@
// the builder. Mark the if instruction as such.
controlFlowOperators.add(startIf);
+ // Find the next non-HGoto instruction following the phi.
+ HInstruction nextInstruction = phi.block.first;
+ while (nextInstruction is HGoto) {
+ nextInstruction = nextInstruction.block.successors[0].first;
+ }
+
// If the operation is only used by the first instruction
// of its block and is safe to be generated at use site, mark it
// so.
if (phi.usedBy.length == 1
- && identical(phi.usedBy[0], phi.block.first)
+ && phi.usedBy[0] == nextInstruction
&& isSafeToGenerateAtUseSite(phi.usedBy[0], phi)) {
markAsGenerateAtUseSite(phi);
}
diff --git a/sdk/lib/_internal/compiler/implementation/ssa/nodes.dart b/sdk/lib/_internal/compiler/implementation/ssa/nodes.dart
index 2eb8faa..088fe6e 100644
--- a/sdk/lib/_internal/compiler/implementation/ssa/nodes.dart
+++ b/sdk/lib/_internal/compiler/implementation/ssa/nodes.dart
@@ -37,6 +37,7 @@
R visitInvokeDynamicSetter(HInvokeDynamicSetter node);
R visitInvokeStatic(HInvokeStatic node);
R visitInvokeSuper(HInvokeSuper node);
+ R visitInvokeConstructorBody(HInvokeConstructorBody node);
R visitIs(HIs node);
R visitLazyStatic(HLazyStatic node);
R visitLess(HLess node);
@@ -303,6 +304,8 @@
visitInterceptor(HInterceptor node) => visitInstruction(node);
visitInvokeClosure(HInvokeClosure node)
=> visitInvokeDynamic(node);
+ visitInvokeConstructorBody(HInvokeConstructorBody node)
+ => visitInvokeStatic(node);
visitInvokeDynamicMethod(HInvokeDynamicMethod node)
=> visitInvokeDynamic(node);
visitInvokeDynamicGetter(HInvokeDynamicGetter node)
@@ -310,7 +313,7 @@
visitInvokeDynamicSetter(HInvokeDynamicSetter node)
=> visitInvokeDynamicField(node);
visitInvokeStatic(HInvokeStatic node) => visitInvoke(node);
- visitInvokeSuper(HInvokeSuper node) => visitInvoke(node);
+ visitInvokeSuper(HInvokeSuper node) => visitInvokeStatic(node);
visitJump(HJump node) => visitControlFlow(node);
visitLazyStatic(HLazyStatic node) => visitInstruction(node);
visitLess(HLess node) => visitRelational(node);
@@ -1083,6 +1086,15 @@
HInstruction convertType(Compiler compiler, DartType type, int kind) {
if (type == null) return this;
+ // Only the builder knows how to create [HTypeConversion]
+ // instructions with generics. It has the generic type context
+ // available.
+ assert(type.kind != TypeKind.TYPE_VARIABLE);
+ // TODO(5022): Generic typedefs should not be handled here.
+ assert(type.isRaw
+ || type.isMalformed
+ || type.kind == TypeKind.TYPEDEF
+ || type.kind == TypeKind.FUNCTION);
if (identical(type.element, compiler.dynamicClass)) return this;
if (identical(type.element, compiler.objectClass)) return this;
if (type.isMalformed || type.kind != TypeKind.INTERFACE) {
@@ -1399,6 +1411,14 @@
}
}
+class HInvokeConstructorBody extends HInvokeStatic {
+ HInvokeConstructorBody(element, inputs)
+ : super(element, inputs, HType.UNKNOWN);
+
+ String toString() => 'invoke constructor body: ${element.name}';
+ accept(HVisitor visitor) => visitor.visitInvokeConstructorBody(this);
+}
+
abstract class HFieldAccess extends HInstruction {
final Element element;
diff --git a/sdk/lib/_internal/compiler/implementation/ssa/optimize.dart b/sdk/lib/_internal/compiler/implementation/ssa/optimize.dart
index 09df7c1..26523a5 100644
--- a/sdk/lib/_internal/compiler/implementation/ssa/optimize.dart
+++ b/sdk/lib/_internal/compiler/implementation/ssa/optimize.dart
@@ -1586,8 +1586,7 @@
element, node.inputs[j].instructionType);
j++;
},
- includeBackendMembers: false,
- includeSuperMembers: true);
+ includeSuperAndInjectedMembers: true);
}
visitFieldSet(HFieldSet node) {
diff --git a/sdk/lib/_internal/compiler/implementation/ssa/tracer.dart b/sdk/lib/_internal/compiler/implementation/ssa/tracer.dart
index f11f5d5..02d7cfe 100644
--- a/sdk/lib/_internal/compiler/implementation/ssa/tracer.dart
+++ b/sdk/lib/_internal/compiler/implementation/ssa/tracer.dart
@@ -355,9 +355,7 @@
String visitInvokeStatic(HInvokeStatic invoke) {
String target = invoke.element.name.slowToString();
- int offset = HInvoke.ARGUMENTS_OFFSET;
- List arguments = invoke.inputs.sublist(offset);
- return visitGenericInvoke("Invoke", target, arguments);
+ return visitGenericInvoke("Invoke", target, invoke.inputs);
}
String visitInvokeSuper(HInvokeSuper invoke) {
@@ -367,6 +365,13 @@
return visitGenericInvoke("Invoke super", target, arguments);
}
+ String visitInvokeConstructorBody(HInvokeConstructorBody invoke) {
+ String target = invoke.element.name.slowToString();
+ int offset = HInvoke.ARGUMENTS_OFFSET + 1;
+ List arguments = invoke.inputs.sublist(offset);
+ return visitGenericInvoke("Invoke constructor body", target, arguments);
+ }
+
String visitForeign(HForeign foreign) {
return visitGenericInvoke("Foreign", "${foreign.codeAst}", foreign.inputs);
}
diff --git a/sdk/lib/_internal/compiler/implementation/ssa/types.dart b/sdk/lib/_internal/compiler/implementation/ssa/types.dart
index 20a0b64..d1d22bf 100644
--- a/sdk/lib/_internal/compiler/implementation/ssa/types.dart
+++ b/sdk/lib/_internal/compiler/implementation/ssa/types.dart
@@ -18,11 +18,13 @@
return isNullable ? HType.NULL : HType.CONFLICTING;
}
+ JavaScriptBackend backend = compiler.backend;
if (mask.containsOnlyInt(compiler)) {
return isNullable ? HType.INTEGER_OR_NULL : HType.INTEGER;
} else if (mask.containsOnlyDouble(compiler)) {
return isNullable ? HType.DOUBLE_OR_NULL : HType.DOUBLE;
- } else if (mask.containsOnlyNum(compiler)) {
+ } else if (mask.containsOnlyNum(compiler)
+ || mask.satisfies(backend.jsNumberClass, compiler)) {
return isNullable ? HType.NUMBER_OR_NULL : HType.NUMBER;
} else if (mask.containsOnlyString(compiler)) {
return isNullable ? HType.STRING_OR_NULL : HType.STRING;
@@ -38,18 +40,17 @@
return isNullable ? HType.UNKNOWN : HType.NON_NULL;
}
- JavaScriptBackend backend = compiler.backend;
if (!isNullable) {
- if (mask.containsOnly(backend.jsIndexableClass)) {
- return HType.INDEXABLE_PRIMITIVE;
- } else if (mask.containsOnly(backend.jsArrayClass)) {
- return HType.READABLE_ARRAY;
- } else if (mask.containsOnly(backend.jsMutableArrayClass)) {
- return HType.MUTABLE_ARRAY;
- } else if (mask.containsOnly(backend.jsFixedArrayClass)) {
+ if (mask.containsOnly(backend.jsFixedArrayClass)) {
return HType.FIXED_ARRAY;
} else if (mask.containsOnly(backend.jsExtendableArrayClass)) {
return HType.EXTENDABLE_ARRAY;
+ } else if (mask.satisfies(backend.jsMutableArrayClass, compiler)) {
+ return HType.MUTABLE_ARRAY;
+ } else if (mask.satisfies(backend.jsArrayClass, compiler)) {
+ return HType.READABLE_ARRAY;
+ } else if (mask.satisfies(backend.jsIndexableClass, compiler)) {
+ return HType.INDEXABLE_PRIMITIVE;
}
}
return new HBoundedType(mask);
@@ -270,6 +271,8 @@
TypeMask union = mask.union(otherMask, compiler);
return new HType.fromMask(union, compiler);
}
+
+ HType simplify(Compiler compiler) => this;
}
/** Used to represent [HType.UNKNOWN] and [HType.CONFLICTING]. */
@@ -561,7 +564,11 @@
bool canBePrimitiveNumber(Compiler compiler) {
JavaScriptBackend backend = compiler.backend;
DartType jsNumberType = backend.jsNumberClass.computeType(compiler);
- return mask.contains(jsNumberType, compiler);
+ DartType jsIntType = backend.jsIntClass.computeType(compiler);
+ DartType jsDoubleType = backend.jsDoubleClass.computeType(compiler);
+ return mask.contains(jsNumberType, compiler)
+ || mask.contains(jsIntType, compiler)
+ || mask.contains(jsDoubleType, compiler);
}
bool canBePrimitiveBoolean(Compiler compiler) {
@@ -588,6 +595,10 @@
TypeMask computeMask(Compiler compiler) => mask;
+ HType simplify(Compiler compiler) {
+ return new HType.fromMask(mask.simplify(compiler), compiler);
+ }
+
bool operator ==(HType other) {
if (other is !HBoundedType) return false;
HBoundedType bounded = other;
diff --git a/sdk/lib/_internal/compiler/implementation/typechecker.dart b/sdk/lib/_internal/compiler/implementation/typechecker.dart
index 24faf77..b58a0eb 100644
--- a/sdk/lib/_internal/compiler/implementation/typechecker.dart
+++ b/sdk/lib/_internal/compiler/implementation/typechecker.dart
@@ -18,6 +18,22 @@
}
/**
+ * Class used to report different warnings for differrent kinds of members.
+ */
+class MemberKind {
+ static const MemberKind METHOD = const MemberKind("method");
+ static const MemberKind OPERATOR = const MemberKind("operator");
+ static const MemberKind PROPERTY = const MemberKind("property");
+
+ final String name;
+
+ const MemberKind(this.name);
+
+ String toString() => name;
+}
+
+
+/**
* [ElementAccess] represents the access of [element], either as a property
* access or invocation.
*/
@@ -49,6 +65,8 @@
Element get element => member.element;
DartType computeType(Compiler compiler) => member.computeType(compiler);
+
+ String toString() => 'MemberAccess($member)';
}
/// An access of an unresolved element.
@@ -60,6 +78,8 @@
DartType computeType(Compiler compiler) => compiler.types.dynamicType;
bool isCallable(Compiler compiler) => true;
+
+ String toString() => 'DynamicAccess';
}
/**
@@ -73,7 +93,19 @@
assert(element != null);
}
- DartType computeType(Compiler compiler) => element.computeType(compiler);
+ DartType computeType(Compiler compiler) {
+ if (element.isGetter()) {
+ FunctionType functionType = element.computeType(compiler);
+ return functionType.returnType;
+ } else if (element.isSetter()) {
+ FunctionType functionType = element.computeType(compiler);
+ return functionType.parameterTypes.head;
+ } else {
+ return element.computeType(compiler);
+ }
+ }
+
+ String toString() => 'ResolvedAccess($element)';
}
/**
@@ -89,6 +121,23 @@
Element get element => type.element;
DartType computeType(Compiler compiler) => type;
+
+ String toString() => 'TypeAccess($type)';
+}
+
+/**
+ * An access of a type literal.
+ */
+class TypeLiteralAccess extends ElementAccess {
+ final Element element;
+ TypeLiteralAccess(Element this.element) {
+ assert(element != null);
+ }
+
+ DartType computeType(Compiler compiler) =>
+ compiler.typeClass.computeType(compiler);
+
+ String toString() => 'TypeLiteralAccess($element)';
}
class TypeCheckerVisitor implements Visitor<DartType> {
@@ -98,7 +147,7 @@
Node lastSeenNode;
DartType expectedReturnType;
- ClassElement currentClass;
+ final ClassElement currentClass;
Link<DartType> cascadeTypes = const Link<DartType>();
@@ -109,7 +158,10 @@
DartType objectType;
DartType listType;
- TypeCheckerVisitor(this.compiler, this.elements, this.types) {
+ TypeCheckerVisitor(this.compiler, TreeElements elements, this.types)
+ : this.elements = elements,
+ currentClass = elements.currentElement != null
+ ? elements.currentElement.getEnclosingClass() : null {
intType = compiler.intClass.computeType(compiler);
doubleType = compiler.doubleClass.computeType(compiler);
boolType = compiler.boolClass.computeType(compiler);
@@ -122,6 +174,11 @@
compiler.reportWarning(node, new TypeWarning(kind, arguments));
}
+ reportTypeInfo(Spannable node, MessageKind kind, [Map arguments = const {}]) {
+ compiler.reportDiagnostic(compiler.spanFromSpannable(node),
+ 'Info: ${kind.message(arguments)}', api.Diagnostic.INFO);
+ }
+
// TODO(karlklose): remove these functions.
DartType unhandledStatement() => StatementType.NOT_RETURNING;
DartType unhandledExpression() => types.dynamicType;
@@ -160,15 +217,17 @@
* Check if a value of type t can be assigned to a variable,
* parameter or return value of type s.
*/
- checkAssignable(Node node, DartType s, DartType t) {
- if (!types.isAssignable(s, t)) {
+ bool checkAssignable(Node node, DartType from, DartType to) {
+ if (!types.isAssignable(from, to)) {
reportTypeWarning(node, MessageKind.NOT_ASSIGNABLE,
- {'fromType': s, 'toType': t});
+ {'fromType': from, 'toType': to});
+ return false;
}
+ return true;
}
checkCondition(Expression condition) {
- checkAssignable(condition, boolType, analyze(condition));
+ checkAssignable(condition, analyze(condition), boolType);
}
void pushCascadeType(DartType type) {
@@ -260,7 +319,6 @@
}
DartType previous = expectedReturnType;
expectedReturnType = returnType;
- if (element.isMember()) currentClass = element.getEnclosingClass();
StatementType bodyType = analyze(node.body);
if (returnType != types.voidType && returnType != types.dynamicType
&& bodyType != StatementType.RETURNING) {
@@ -297,7 +355,8 @@
return unhandledStatement();
}
- ElementAccess lookupMethod(Node node, DartType type, SourceString name) {
+ ElementAccess lookupMember(Node node, DartType type, SourceString name,
+ MemberKind memberKind) {
if (identical(type, types.dynamicType)) {
return const DynamicAccess();
}
@@ -305,17 +364,35 @@
if (member != null) {
return new MemberAccess(member);
}
- reportTypeWarning(node, MessageKind.METHOD_NOT_FOUND,
- {'className': type.name, 'memberName': name});
+ switch (memberKind) {
+ case MemberKind.METHOD:
+ reportTypeWarning(node, MessageKind.METHOD_NOT_FOUND,
+ {'className': type.name, 'memberName': name});
+ break;
+ case MemberKind.OPERATOR:
+ reportTypeWarning(node, MessageKind.OPERATOR_NOT_FOUND,
+ {'className': type.name, 'memberName': name});
+ break;
+ case MemberKind.PROPERTY:
+ reportTypeWarning(node, MessageKind.PROPERTY_NOT_FOUND,
+ {'className': type.name, 'memberName': name});
+ break;
+ }
return const DynamicAccess();
}
- // TODO(johnniwinther): Provide the element from which the type came in order
- // to give better error messages.
- void analyzeArguments(Send send, DartType type) {
+ DartType lookupMemberType(Node node, DartType type, SourceString name,
+ MemberKind memberKind) {
+ return lookupMember(node, type, name, memberKind).computeType(compiler);
+ }
+
+ void analyzeArguments(Send send, Element element, DartType type,
+ [LinkBuilder<DartType> argumentTypes]) {
Link<Node> arguments = send.arguments;
DartType unaliasedType = type.unalias(compiler);
if (identical(unaliasedType.kind, TypeKind.FUNCTION)) {
+ assert(invariant(send, element != null, message: 'No element for $send'));
+ bool error = false;
FunctionType funType = unaliasedType;
Link<DartType> parameterTypes = funType.parameterTypes;
Link<DartType> optionalParameterTypes = funType.optionalParameterTypes;
@@ -328,57 +405,80 @@
DartType namedParameterType =
funType.getNamedParameterType(argumentName);
if (namedParameterType == null) {
+ error = true;
// TODO(johnniwinther): Provide better information on the called
// function.
reportTypeWarning(argument, MessageKind.NAMED_ARGUMENT_NOT_FOUND,
{'argumentName': argumentName});
- analyze(argument);
+ DartType argumentType = analyze(argument);
+ if (argumentTypes != null) argumentTypes.addLast(argumentType);
} else {
- checkAssignable(argument, namedParameterType, analyze(argument));
+ DartType argumentType = analyze(argument);
+ if (argumentTypes != null) argumentTypes.addLast(argumentType);
+ if (!checkAssignable(argument, argumentType, namedParameterType)) {
+ error = true;
+ }
}
} else {
if (parameterTypes.isEmpty) {
if (optionalParameterTypes.isEmpty) {
+ error = true;
// TODO(johnniwinther): Provide better information on the
// called function.
reportTypeWarning(argument, MessageKind.ADDITIONAL_ARGUMENT);
- analyze(argument);
+ DartType argumentType = analyze(argument);
+ if (argumentTypes != null) argumentTypes.addLast(argumentType);
} else {
- checkAssignable(argument, optionalParameterTypes.head,
- analyze(argument));
+ DartType argumentType = analyze(argument);
+ if (argumentTypes != null) argumentTypes.addLast(argumentType);
+ if (!checkAssignable(argument,
+ argumentType, optionalParameterTypes.head)) {
+ error = true;
+ }
optionalParameterTypes = optionalParameterTypes.tail;
}
} else {
- checkAssignable(argument, parameterTypes.head, analyze(argument));
+ DartType argumentType = analyze(argument);
+ if (argumentTypes != null) argumentTypes.addLast(argumentType);
+ if (!checkAssignable(argument, argumentType, parameterTypes.head)) {
+ error = true;
+ }
parameterTypes = parameterTypes.tail;
}
}
arguments = arguments.tail;
}
if (!parameterTypes.isEmpty) {
+ error = true;
// TODO(johnniwinther): Provide better information on the called
// function.
reportTypeWarning(send, MessageKind.MISSING_ARGUMENT,
{'argumentType': parameterTypes.head});
}
+ if (error) {
+ reportTypeInfo(element, MessageKind.THIS_IS_THE_METHOD);
+ }
} else {
while(!arguments.isEmpty) {
- analyze(arguments.head);
+ DartType argumentType = analyze(arguments.head);
+ if (argumentTypes != null) argumentTypes.addLast(argumentType);
arguments = arguments.tail;
}
}
}
- DartType analyzeInvocation(Send node, ElementAccess elementAccess) {
+ DartType analyzeInvocation(Send node, ElementAccess elementAccess,
+ [LinkBuilder<DartType> argumentTypes]) {
DartType type = elementAccess.computeType(compiler);
if (elementAccess.isCallable(compiler)) {
- analyzeArguments(node, type);
+ analyzeArguments(node, elementAccess.element, type, argumentTypes);
} else {
reportTypeWarning(node, MessageKind.NOT_CALLABLE,
{'elementName': elementAccess.element.name});
- analyzeArguments(node, types.dynamicType);
+ analyzeArguments(node, elementAccess.element, types.dynamicType,
+ argumentTypes);
}
if (identical(type.kind, TypeKind.FUNCTION)) {
FunctionType funType = type;
@@ -388,6 +488,104 @@
}
}
+ /**
+ * Computes the [ElementAccess] for [name] on the [node] possibly using the
+ * [element] provided for [node] by the resolver.
+ */
+ ElementAccess computeAccess(Send node, SourceString name, Element element,
+ MemberKind memberKind) {
+ if (node.receiver != null) {
+ Element receiverElement = elements[node.receiver];
+ if (receiverElement != null) {
+ if (receiverElement.isPrefix()) {
+ assert(invariant(node, element != null,
+ message: 'Prefixed node has no element.'));
+ return computeResolvedAccess(node, name, element, memberKind);
+ }
+ }
+ // e.foo() for some expression e.
+ DartType receiverType = analyze(node.receiver);
+ if (receiverType.isDynamic ||
+ receiverType.isMalformed ||
+ receiverType.isVoid) {
+ 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);
+ }
+ }
+
+ /**
+ * Computes the [ElementAccess] for [name] on the [node] using the [element]
+ * provided for [node] by the resolver.
+ */
+ ElementAccess computeResolvedAccess(Send node, SourceString name,
+ Element element, MemberKind memberKind) {
+ if (Elements.isUnresolved(element)) {
+ // foo() where foo is unresolved.
+ return const DynamicAccess();
+ } else if (element.isMember()) {
+ // foo() where foo is an instance member.
+ return lookupMember(node, currentClass.computeType(compiler),
+ name, memberKind);
+ } else if (element.isFunction()) {
+ // foo() where foo is a method in the same class.
+ return new ResolvedAccess(element);
+ } else if (element.isVariable() ||
+ element.isParameter() ||
+ element.isField()) {
+ // foo() where foo is a field in the same class.
+ return new ResolvedAccess(element);
+ } else if (element.impliesType()) {
+ // The literal `Foo` where Foo is a class, a typedef, or a type variable.
+ if (elements.getType(node) != null) {
+ assert(invariant(node, identical(compiler.typeClass,
+ elements.getType(node).element),
+ message: 'Expected type literal type: '
+ '${elements.getType(node)}'));
+ return new TypeLiteralAccess(element);
+ }
+ return new ResolvedAccess(element);
+ } else if (element.isGetter() || element.isSetter()) {
+ return new ResolvedAccess(element);
+ } else {
+ compiler.internalErrorOnElement(
+ element, 'unexpected element kind ${element.kind}');
+ }
+ }
+
+ /**
+ * Computes the type of the access of [name] on the [node] possibly using the
+ * [element] provided for [node] by the resolver.
+ */
+ DartType computeAccessType(Send node, SourceString name, Element element,
+ MemberKind memberKind) {
+ DartType type =
+ computeAccess(node, name, element, memberKind).computeType(compiler);
+ if (type == null) {
+ compiler.internalError('type is null on access of $name on $node',
+ node: node);
+ }
+ return type;
+ }
+
DartType visitSend(Send node) {
Element element = elements[node];
@@ -408,117 +606,252 @@
if (node.isOperator && identical(name, 'is')) {
analyze(node.receiver);
return boolType;
+ } if (node.isOperator && identical(name, 'as')) {
+ analyze(node.receiver);
+ return elements.getType(node.arguments.head);
} else if (node.isOperator) {
- final Node firstArgument = node.receiver;
- final DartType firstArgumentType = analyze(node.receiver);
- final arguments = node.arguments;
- final Node secondArgument = arguments.isEmpty ? null : arguments.head;
- final DartType secondArgumentType =
- analyzeWithDefault(secondArgument, null);
-
- if (identical(name, '+') || identical(name, '=') ||
- identical(name, '-') || identical(name, '*') ||
- identical(name, '/') || identical(name, '%') ||
- identical(name, '~/') || identical(name, '|') ||
- identical(name, '&') || identical(name, '^') ||
- identical(name, '~')|| identical(name, '<<') ||
- identical(name, '>>') || identical(name, '[]')) {
- return types.dynamicType;
- } else if (identical(name, '<') || identical(name, '>') ||
- identical(name, '<=') || identical(name, '>=') ||
- identical(name, '==') || identical(name, '!=') ||
- identical(name, '===') || identical(name, '!==')) {
+ final Node receiver = node.receiver;
+ final DartType receiverType = analyze(receiver);
+ if (identical(name, '==') || identical(name, '!=')
+ // TODO(johnniwinther): Remove these.
+ || identical(name, '===') || identical(name, '!==')) {
+ // Analyze argument.
+ analyze(node.arguments.head);
return boolType;
} else if (identical(name, '||') ||
- identical(name, '&&') ||
- identical(name, '!')) {
- checkAssignable(firstArgument, boolType, firstArgumentType);
- if (!arguments.isEmpty) {
- // TODO(karlklose): check number of arguments in validator.
- checkAssignable(secondArgument, boolType, secondArgumentType);
- }
+ identical(name, '&&')) {
+ checkAssignable(receiver, receiverType, boolType);
+ final Node argument = node.arguments.head;
+ final DartType argumentType = analyze(argument);
+ checkAssignable(argument, argumentType, boolType);
return boolType;
- } else {
- return unhandledExpression();
+ } else if (identical(name, '!')) {
+ checkAssignable(receiver, receiverType, boolType);
+ return boolType;
+ } else if (identical(name, '?')) {
+ return boolType;
}
+ SourceString operatorName = selector.source;
+ if (identical(name, '-') && node.arguments.isEmpty) {
+ operatorName = const SourceString('unary-');
+ }
+ assert(invariant(node,
+ identical(name, '+') || identical(name, '=') ||
+ identical(name, '-') || identical(name, '*') ||
+ identical(name, '/') || identical(name, '%') ||
+ identical(name, '~/') || identical(name, '|') ||
+ identical(name, '&') || identical(name, '^') ||
+ identical(name, '~')|| identical(name, '<<') ||
+ identical(name, '>>') ||
+ identical(name, '<') || identical(name, '>') ||
+ identical(name, '<=') || identical(name, '>=') ||
+ identical(name, '[]'),
+ message: 'Unexpected operator $name'));
+ ElementAccess access = lookupMember(node, receiverType,
+ operatorName, MemberKind.OPERATOR);
+ LinkBuilder<DartType> argumentTypesBuilder = new LinkBuilder<DartType>();
+ DartType resultType =
+ analyzeInvocation(node, access, argumentTypesBuilder);
+ if (identical(receiverType.element, compiler.intClass)) {
+ if (identical(name, '+') ||
+ identical(operatorName, const SourceString('-')) ||
+ identical(name, '*') ||
+ identical(name, '%')) {
+ DartType argumentType = argumentTypesBuilder.toLink().head;
+ if (identical(argumentType.element, compiler.intClass)) {
+ return intType;
+ } else if (identical(argumentType.element, compiler.doubleClass)) {
+ return doubleType;
+ }
+ }
+ }
+ return resultType;
} else if (node.isPropertyAccess) {
- if (node.receiver != null) {
- // TODO(karlklose): we cannot handle fields.
- return unhandledExpression();
- }
- if (element == null) return types.dynamicType;
- return computeType(element);
-
+ ElementAccess access =
+ computeAccess(node, selector.source, element, MemberKind.PROPERTY);
+ return access.computeType(compiler);
} else if (node.isFunctionObjectInvocation) {
return unhandledExpression();
} else {
- ElementAccess computeMethod() {
- if (node.receiver != null) {
- // e.foo() for some expression e.
- DartType receiverType = analyze(node.receiver);
- if (receiverType.element == compiler.dynamicClass ||
- receiverType == null ||
- receiverType.isMalformed ||
- receiverType.isVoid) {
- return const DynamicAccess();
- }
- TypeKind receiverKind = receiverType.kind;
- if (identical(receiverKind, TypeKind.TYPEDEF)) {
- // TODO(karlklose): handle typedefs.
- return const DynamicAccess();
- }
- if (identical(receiverKind, TypeKind.TYPE_VARIABLE)) {
- // TODO(karlklose): handle type variables.
- return const DynamicAccess();
- }
- if (identical(receiverKind, TypeKind.FUNCTION)) {
- // TODO(karlklose): handle getters.
- return const DynamicAccess();
- }
- assert(invariant(node.receiver,
- identical(receiverKind, TypeKind.INTERFACE),
- message: "interface type expected, got ${receiverKind}"));
- return lookupMethod(selector, receiverType, selector.source);
- } else {
- if (Elements.isUnresolved(element)) {
- // foo() where foo is unresolved.
- return const DynamicAccess();
- } else if (element.isFunction()) {
- // foo() where foo is a method in the same class.
- return new ResolvedAccess(element);
- } else if (element.isVariable() || element.isField()) {
- // foo() where foo is a field in the same class.
- return new ResolvedAccess(element);
- } else if (element.isGetter()) {
- // TODO(karlklose): handle getters.
- return const DynamicAccess();
- } else if (element.isClass()) {
- // TODO(karlklose): handle type literals.
- return const DynamicAccess();
- } else {
- compiler.internalErrorOnElement(
- element, 'unexpected element kind ${element.kind}');
- }
- }
- }
- return analyzeInvocation(node, computeMethod());
+ ElementAccess access =
+ computeAccess(node, selector.source, element, MemberKind.METHOD);
+ return analyzeInvocation(node, access);
}
}
+ /**
+ * Checks [: target o= value :] for some operator o, and returns the type
+ * of the result. This method also handles increment/decrement expressions
+ * like [: target++ :].
+ */
+ DartType checkAssignmentOperator(SendSet node,
+ SourceString operatorName,
+ Node valueNode,
+ DartType value) {
+ assert(invariant(node, !node.isIndex));
+ Element element = elements[node];
+ Identifier selector = node.selector;
+ DartType target =
+ computeAccessType(node, selector.source, element, MemberKind.PROPERTY);
+ // [operator] is the type of operator+ or operator- on [target].
+ DartType operator =
+ lookupMemberType(node, target, operatorName, MemberKind.OPERATOR);
+ if (operator is FunctionType) {
+ FunctionType operatorType = operator;
+ // [result] is the type of target o value.
+ DartType result = operatorType.returnType;
+ DartType operatorArgument = operatorType.parameterTypes.head;
+ // Check target o value.
+ bool validValue = checkAssignable(valueNode, value, operatorArgument);
+ if (validValue || !(node.isPrefix || node.isPostfix)) {
+ // Check target = result.
+ checkAssignable(node.assignmentOperator, result, target);
+ }
+ return node.isPostfix ? target : result;
+ }
+ return types.dynamicType;
+ }
+
+ /**
+ * Checks [: base[key] o= value :] for some operator o, and returns the type
+ * of the result. This method also handles increment/decrement expressions
+ * like [: base[key]++ :].
+ */
+ DartType checkIndexAssignmentOperator(SendSet node,
+ SourceString operatorName,
+ Node valueNode,
+ DartType value) {
+ assert(invariant(node, node.isIndex));
+ final DartType base = analyze(node.receiver);
+ final Node keyNode = node.arguments.head;
+ final DartType key = analyze(keyNode);
+
+ // [indexGet] is the type of operator[] on [base].
+ DartType indexGet = lookupMemberType(
+ node, base, const SourceString('[]'), MemberKind.OPERATOR);
+ if (indexGet is FunctionType) {
+ FunctionType indexGetType = indexGet;
+ DartType indexGetKey = indexGetType.parameterTypes.head;
+ // Check base[key].
+ bool validKey = checkAssignable(keyNode, key, indexGetKey);
+
+ // [element] is the type of base[key].
+ DartType element = indexGetType.returnType;
+ // [operator] is the type of operator o on [element].
+ DartType operator = lookupMemberType(
+ node, element, operatorName, MemberKind.OPERATOR);
+ if (operator is FunctionType) {
+ FunctionType operatorType = operator;
+
+ // Check base[key] o value.
+ DartType operatorArgument = operatorType.parameterTypes.head;
+ bool validValue = checkAssignable(valueNode, value, operatorArgument);
+
+ // [result] is the type of base[key] o value.
+ DartType result = operatorType.returnType;
+
+ // [indexSet] is the type of operator[]= on [base].
+ DartType indexSet = lookupMemberType(
+ node, base, const SourceString('[]='), MemberKind.OPERATOR);
+ if (indexSet is FunctionType) {
+ FunctionType indexSetType = indexSet;
+ DartType indexSetKey = indexSetType.parameterTypes.head;
+ DartType indexSetValue =
+ indexSetType.parameterTypes.tail.head;
+
+ if (validKey || indexGetKey != indexSetKey) {
+ // Only check base[key] on []= if base[key] was valid for [] or
+ // if the key types differ.
+ checkAssignable(keyNode, key, indexSetKey);
+ }
+ // Check base[key] = result
+ if (validValue || !(node.isPrefix || node.isPostfix)) {
+ checkAssignable(node.assignmentOperator, result, indexSetValue);
+ }
+ }
+ return node.isPostfix ? element : result;
+ }
+ }
+ return types.dynamicType;
+ }
+
visitSendSet(SendSet node) {
+ Element element = elements[node];
Identifier selector = node.selector;
final name = node.assignmentOperator.source.stringValue;
- if (identical(name, '++') || identical(name, '--')) {
- final Element element = elements[node.selector];
- final DartType receiverType = computeType(element);
- // TODO(karlklose): this should be the return type instead of int.
- return node.isPrefix ? intType : receiverType;
+ if (identical(name, '=')) {
+ // e1 = value
+ if (node.isIndex) {
+ // base[key] = value
+ final DartType base = analyze(node.receiver);
+ final Node keyNode = node.arguments.head;
+ final DartType key = analyze(keyNode);
+ final Node valueNode = node.arguments.tail.head;
+ final DartType value = analyze(valueNode);
+ DartType indexSet = lookupMemberType(
+ node, base, const SourceString('[]='), MemberKind.OPERATOR);
+ if (indexSet is FunctionType) {
+ FunctionType indexSetType = indexSet;
+ DartType indexSetKey = indexSetType.parameterTypes.head;
+ checkAssignable(keyNode, key, indexSetKey);
+ DartType indexSetValue = indexSetType.parameterTypes.tail.head;
+ checkAssignable(node.assignmentOperator, value, indexSetValue);
+ }
+ return value;
+ } else {
+ // target = value
+ DartType target = computeAccessType(node, selector.source,
+ element, MemberKind.PROPERTY);
+ final Node valueNode = node.arguments.head;
+ final DartType value = analyze(valueNode);
+ checkAssignable(node.assignmentOperator, value, target);
+ return value;
+ }
+ } else if (identical(name, '++') || identical(name, '--')) {
+ // e++ or e--
+ SourceString operatorName = identical(name, '++')
+ ? const SourceString('+') : const SourceString('-');
+ if (node.isIndex) {
+ // base[key]++, base[key]--, ++base[key], or --base[key]
+ return checkIndexAssignmentOperator(
+ node, operatorName, node.assignmentOperator, intType);
+ } else {
+ // target++, target--, ++target, or --target
+ return checkAssignmentOperator(
+ node, operatorName, node.assignmentOperator, intType);
+ }
} else {
- DartType targetType = computeType(elements[node]);
- Node value = node.arguments.head;
- checkAssignable(value, targetType, analyze(value));
- return targetType;
+ // e1 o= e2 for some operator o.
+ SourceString operatorName;
+ switch (name) {
+ case '+=': operatorName = const SourceString('+'); break;
+ case '-=': operatorName = const SourceString('-'); break;
+ case '*=': operatorName = const SourceString('*'); break;
+ case '/=': operatorName = const SourceString('/'); break;
+ case '%=': operatorName = const SourceString('%'); break;
+ case '~/=': operatorName = const SourceString('~/'); break;
+ case '&=': operatorName = const SourceString('&'); break;
+ case '|=': operatorName = const SourceString('|'); break;
+ case '^=': operatorName = const SourceString('^'); break;
+ case '<<=': operatorName = const SourceString('<<'); break;
+ case '>>=': operatorName = const SourceString('>>'); break;
+ default:
+ compiler.internalError(
+ 'Unexpected assignment operator $name', node: node);
+ }
+ if (node.isIndex) {
+ // base[key] o= value for some operator o.
+ final Node valueNode = node.arguments.tail.head;
+ final DartType value = analyze(valueNode);
+ return checkIndexAssignmentOperator(
+ node, operatorName, valueNode, value);
+ } else {
+ // target o= value for some operator o.
+ final Node valueNode = node.arguments.head;
+ final DartType value = analyze(valueNode);
+ return checkAssignmentOperator(node, operatorName, valueNode, value);
+ }
}
}
@@ -550,11 +883,30 @@
DartType visitNewExpression(NewExpression node) {
Element element = elements[node.send];
- analyzeArguments(node.send, computeType(element));
- return analyze(node.send.selector);
+ DartType constructorType = computeType(element);
+ DartType newType = elements.getType(node);
+ // TODO(johnniwinther): Use [:lookupMember:] to account for type variable
+ // substitution of parameter types.
+ if (identical(newType.kind, TypeKind.INTERFACE)) {
+ InterfaceType newInterfaceType = newType;
+ constructorType = constructorType.subst(
+ newInterfaceType.typeArguments,
+ newInterfaceType.element.typeVariables);
+ }
+ analyzeArguments(node.send, element, constructorType);
+ return newType;
}
DartType visitLiteralList(LiteralList node) {
+ InterfaceType listType = elements.getType(node);
+ DartType listElementType = listType.typeArguments.head;
+ for (Link<Node> link = node.elements.nodes;
+ !link.isEmpty;
+ link = link.tail) {
+ Node element = link.head;
+ DartType elementType = analyze(element);
+ checkAssignable(element, elementType, listElementType);
+ }
return listType;
}
@@ -610,7 +962,7 @@
&& !types.isAssignable(expressionType, types.voidType)) {
reportTypeWarning(expression, MessageKind.RETURN_VALUE_IN_VOID);
} else {
- checkAssignable(expression, expectedReturnType, expressionType);
+ checkAssignable(expression, expressionType, expectedReturnType);
}
// Let f be the function immediately enclosing a return statement of the
@@ -630,6 +982,7 @@
return types.dynamicType;
}
+ // TODO(johnniwinther): Remove this.
DartType computeType(Element element) {
if (Elements.isUnresolved(element)) return types.dynamicType;
DartType result = element.computeType(compiler);
@@ -652,12 +1005,12 @@
}
for (Link<Node> link = node.definitions.nodes; !link.isEmpty;
link = link.tail) {
- Node initialization = link.head;
- compiler.ensure(initialization is Identifier
- || initialization is Send);
- if (initialization is Send) {
- DartType initializer = analyzeNonVoid(link.head);
- checkAssignable(node, type, initializer);
+ Node definition = link.head;
+ compiler.ensure(definition is Identifier || definition is SendSet);
+ if (definition is Send) {
+ SendSet initialization = definition;
+ DartType initializer = analyzeNonVoid(initialization.arguments.head);
+ checkAssignable(initialization.assignmentOperator, initializer, type);
}
}
return StatementType.NOT_RETURNING;
@@ -733,7 +1086,19 @@
}
visitLiteralMap(LiteralMap node) {
- return unhandledExpression();
+ InterfaceType mapType = elements.getType(node);
+ DartType mapKeyType = mapType.typeArguments.head;
+ DartType mapValueType = mapType.typeArguments.tail.head;
+ for (Link<Node> link = node.entries.nodes;
+ !link.isEmpty;
+ link = link.tail) {
+ LiteralMapEntry entry = link.head;
+ DartType keyType = analyze(entry.key);
+ checkAssignable(entry.key, keyType, mapKeyType);
+ DartType valueType = analyze(entry.value);
+ checkAssignable(entry.value, valueType, mapValueType);
+ }
+ return mapType;
}
visitLiteralMapEntry(LiteralMapEntry node) {
diff --git a/sdk/lib/_internal/compiler/implementation/types/concrete_types_inferrer.dart b/sdk/lib/_internal/compiler/implementation/types/concrete_types_inferrer.dart
index 2bd8266..501beed 100644
--- a/sdk/lib/_internal/compiler/implementation/types/concrete_types_inferrer.dart
+++ b/sdk/lib/_internal/compiler/implementation/types/concrete_types_inferrer.dart
@@ -851,6 +851,8 @@
if (concreteType == null) return null;
TypeMask typeMask = new TypeMask.nonNullEmpty();
for (BaseType baseType in concreteType.baseTypes) {
+ TypeMask other = baseTypeToTypeMask(baseType);
+ if (other == null) return null;
typeMask = typeMask.union(baseTypeToTypeMask(baseType), compiler);
}
return typeMask;
@@ -1098,7 +1100,7 @@
} else if (type.element == compiler.boolClass) {
concreteType = singletonConcreteType(baseTypes.boolBaseType);
} else {
- Set<ClassElement> subtypes = compiler.world.subtypes[type.element];
+ Set<ClassElement> subtypes = compiler.world.subtypesOf(type.element);
if (subtypes == null) continue;
concreteType = emptyConcreteType;
for (ClassElement subtype in subtypes) {
@@ -1221,7 +1223,7 @@
if (type == null) {
uninitializedFields.add(field);
}
- }, includeSuperMembers: false);
+ });
// handle initializing formals
element.functionSignature.forEachParameter((param) {
diff --git a/sdk/lib/_internal/compiler/implementation/types/flat_type_mask.dart b/sdk/lib/_internal/compiler/implementation/types/flat_type_mask.dart
index 4e2bf37..8f3cda3 100644
--- a/sdk/lib/_internal/compiler/implementation/types/flat_type_mask.dart
+++ b/sdk/lib/_internal/compiler/implementation/types/flat_type_mask.dart
@@ -62,6 +62,7 @@
bool get isEmpty => (flags >> 1) == EMPTY;
bool get isExact => (flags >> 1) == EXACT;
bool get isNullable => (flags & 1) != 0;
+ bool get isUnion => false;
// TODO(kasperl): Get rid of these. They should not be a visible
// part of the implementation because they make it hard to add
@@ -77,6 +78,8 @@
return isNullable ? new FlatTypeMask.internal(base, flags & ~1) : this;
}
+ TypeMask simplify(Compiler compiler) => this;
+
bool contains(DartType type, Compiler compiler) {
if (isEmpty) {
return false;
@@ -126,6 +129,21 @@
return base.element == cls;
}
+ bool satisfies(ClassElement cls, Compiler compiler) {
+ if (isEmpty) {
+ return false;
+ } else if (base.element == cls) {
+ return true;
+ } else if (isExact) {
+ return false;
+ } else if (isSubclass) {
+ return isSubclassOf(base, cls.computeType(compiler).asRaw(), compiler);
+ } else {
+ assert(isSubtype);
+ return isSubtypeOf(base, cls.computeType(compiler).asRaw(), compiler);
+ }
+ }
+
/**
* Returns the [ClassElement] if this type represents a single class,
* otherwise returns `null`. This method is conservative.
@@ -153,23 +171,26 @@
|| identical(base.element, compiler.dynamicClass);
}
- TypeMask union(FlatTypeMask other, Compiler compiler) {
+ TypeMask union(TypeMask other, Compiler compiler) {
+ assert(other != null);
+ if (other is! FlatTypeMask) return other.union(this, compiler);
+ FlatTypeMask flatOther = other;
if (isEmpty) {
- return isNullable ? other.nullable() : other;
- } else if (other.isEmpty) {
- return other.isNullable ? nullable() : this;
- } else if (base == other.base) {
- return unionSame(other, compiler);
- } else if (isSubclassOf(other.base, base, compiler)) {
- return unionSubclass(other, compiler);
- } else if (isSubclassOf(base, other.base, compiler)) {
- return other.unionSubclass(this, compiler);
- } else if (isSubtypeOf(other.base, base, compiler)) {
- return unionSubtype(other, compiler);
- } else if (isSubtypeOf(base, other.base, compiler)) {
- return other.unionSubtype(this, compiler);
+ return isNullable ? flatOther.nullable() : flatOther;
+ } else if (flatOther.isEmpty) {
+ return flatOther.isNullable ? nullable() : this;
+ } else if (base == flatOther.base) {
+ return unionSame(flatOther, compiler);
+ } else if (isSubclassOf(flatOther.base, base, compiler)) {
+ return unionSubclass(flatOther, compiler);
+ } else if (isSubclassOf(base, flatOther.base, compiler)) {
+ return flatOther.unionSubclass(this, compiler);
+ } else if (isSubtypeOf(flatOther.base, base, compiler)) {
+ return unionSubtype(flatOther, compiler);
+ } else if (isSubtypeOf(base, flatOther.base, compiler)) {
+ return flatOther.unionSubtype(this, compiler);
} else {
- return unionDisjoint(other, compiler);
+ return new UnionTypeMask._(<FlatTypeMask>[this, flatOther]);
}
}
@@ -222,78 +243,26 @@
: this;
}
- TypeMask unionDisjoint(FlatTypeMask other, Compiler compiler) {
- assert(base != other.base);
- assert(!isSubtypeOf(base, other.base, compiler));
- assert(!isSubtypeOf(other.base, base, compiler));
- // If either type mask is a subtype type mask, we cannot use a
- // subclass type mask to represent their union.
- bool useSubclass = !isSubtype && !other.isSubtype;
- // Compute the common supertypes of the two types.
- ClassElement thisElement = base.element;
- ClassElement otherElement = other.base.element;
- Iterable<ClassElement> candidates =
- compiler.world.commonSupertypesOf(thisElement, otherElement);
- if (candidates.isEmpty) {
- // TODO(kasperl): Get rid of this check. It can only happen when
- // at least one of the two base types is 'unseen'.
- return new TypeMask(compiler.objectClass.rawType,
- SUBCLASS,
- isNullable || other.isNullable);
- }
- // Compute the best candidate and its kind.
- ClassElement bestElement;
- int bestKind;
- int bestSize;
- for (ClassElement candidate in candidates) {
- Set<ClassElement> subclasses = useSubclass
- ? compiler.world.subclasses[candidate]
- : null;
- int size;
- int kind;
- if (subclasses != null &&
- subclasses.contains(thisElement) &&
- subclasses.contains(otherElement)) {
- // If both [this] and [other] are subclasses of the supertype,
- // then we prefer to construct a subclass type mask because it
- // will always be at least as small as the corresponding
- // subtype type mask.
- kind = SUBCLASS;
- size = subclasses.length;
- assert(size <= compiler.world.subtypes[candidate].length);
- } else {
- kind = SUBTYPE;
- size = compiler.world.subtypes[candidate].length;
- }
- // Update the best candidate if the new one is better.
- if (bestElement == null || size < bestSize) {
- bestElement = candidate;
- bestSize = size;
- bestKind = kind;
- }
- }
- return new TypeMask(bestElement.computeType(compiler),
- bestKind,
- isNullable || other.isNullable);
- }
-
- TypeMask intersection(FlatTypeMask other, Compiler compiler) {
+ TypeMask intersection(TypeMask other, Compiler compiler) {
+ assert(other != null);
+ if (other is! FlatTypeMask) return other.intersection(this, compiler);
+ FlatTypeMask flatOther = other;
if (isEmpty) {
- return other.isNullable ? this : nonNullable();
- } else if (other.isEmpty) {
- return isNullable ? other : other.nonNullable();
- } else if (base == other.base) {
- return intersectionSame(other, compiler);
- } else if (isSubclassOf(other.base, base, compiler)) {
- return intersectionSubclass(other, compiler);
- } else if (isSubclassOf(base, other.base, compiler)) {
- return other.intersectionSubclass(this, compiler);
- } else if (isSubtypeOf(other.base, base, compiler)) {
- return intersectionSubtype(other, compiler);
- } else if (isSubtypeOf(base, other.base, compiler)) {
- return other.intersectionSubtype(this, compiler);
+ return flatOther.isNullable ? this : nonNullable();
+ } else if (flatOther.isEmpty) {
+ return isNullable ? flatOther : other.nonNullable();
+ } else if (base == flatOther.base) {
+ return intersectionSame(flatOther, compiler);
+ } else if (isSubclassOf(flatOther.base, base, compiler)) {
+ return intersectionSubclass(flatOther, compiler);
+ } else if (isSubclassOf(base, flatOther.base, compiler)) {
+ return flatOther.intersectionSubclass(this, compiler);
+ } else if (isSubtypeOf(flatOther.base, base, compiler)) {
+ return intersectionSubtype(flatOther, compiler);
+ } else if (isSubtypeOf(base, flatOther.base, compiler)) {
+ return flatOther.intersectionSubtype(this, compiler);
} else {
- return intersectionDisjoint(other, compiler);
+ return intersectionDisjoint(flatOther, compiler);
}
}
@@ -402,10 +371,10 @@
if (isExact) {
return new Set<ClassElement>()..add(element);
} else if (isSubclass) {
- return compiler.world.subclasses[element];
+ return compiler.world.subclassesOf(element);
} else {
assert(isSubtype);
- return compiler.world.subtypes[element];
+ return compiler.world.subtypesOf(element);
}
}
@@ -510,10 +479,10 @@
if (isExact) {
return false;
} else if (isSubtype) {
- subtypesToCheck = compiler.world.subtypes[cls];
+ subtypesToCheck = compiler.world.subtypesOf(cls);
} else {
assert(isSubclass);
- subtypesToCheck = compiler.world.subclasses[cls];
+ subtypesToCheck = compiler.world.subclassesOf(cls);
}
return subtypesToCheck != null
@@ -562,14 +531,14 @@
static bool isSubclassOf(DartType x, DartType y, Compiler compiler) {
ClassElement xElement = x.element;
ClassElement yElement = y.element;
- Set<ClassElement> subclasses = compiler.world.subclasses[yElement];
+ Set<ClassElement> subclasses = compiler.world.subclassesOf(yElement);
return (subclasses != null) ? subclasses.contains(xElement) : false;
}
static bool isSubtypeOf(DartType x, DartType y, Compiler compiler) {
ClassElement xElement = x.element;
ClassElement yElement = y.element;
- Set<ClassElement> subtypes = compiler.world.subtypes[yElement];
+ Set<ClassElement> subtypes = compiler.world.subtypesOf(yElement);
return (subtypes != null) ? subtypes.contains(xElement) : false;
}
diff --git a/sdk/lib/_internal/compiler/implementation/types/simple_types_inferrer.dart b/sdk/lib/_internal/compiler/implementation/types/simple_types_inferrer.dart
index 658ce4e..587e404 100644
--- a/sdk/lib/_internal/compiler/implementation/types/simple_types_inferrer.dart
+++ b/sdk/lib/_internal/compiler/implementation/types/simple_types_inferrer.dart
@@ -7,7 +7,8 @@
import 'dart:collection' show Queue, LinkedHashSet;
import '../closure.dart' show ClosureClassMap, ClosureScope;
-import '../dart_types.dart' show DartType, FunctionType, TypeKind;
+import '../dart_types.dart'
+ show DartType, InterfaceType, FunctionType, TypeKind;
import '../elements/elements.dart';
import '../native_handler.dart' as native;
import '../tree/tree.dart';
@@ -113,12 +114,12 @@
throw 'Unsupported operation';
}
- bool get isNullable => true;
-
TypeMask intersection(TypeMask other, Compiler compiler) {
return other;
}
+ bool get isNullable => true;
+
String toString() => '$name sentinel type mask';
}
@@ -265,7 +266,7 @@
* Sentinel used by the inferrer to notify that it does not know
* the type of a specific element.
*/
- TypeMask dynamicType = new SentinelTypeMask('dynamic');
+ TypeMask dynamicType;
bool isDynamicType(TypeMask type) => identical(type, dynamicType);
TypeMask nullType;
@@ -547,6 +548,8 @@
rawTypeOf(backend.functionImplementation));
typeType = new TypeMask.nonNullExact(
rawTypeOf(backend.typeImplementation));
+
+ dynamicType = new TypeMask.subclass(rawTypeOf(compiler.objectClass));
}
dump() {
@@ -623,6 +626,9 @@
bool recordType(Element analyzedElement, TypeMask type) {
assert(type != null);
+ assert(analyzedElement.isField()
+ || analyzedElement.isParameter()
+ || analyzedElement.isFieldParameter());
return internalRecordType(analyzedElement, type, typeOf);
}
@@ -653,6 +659,18 @@
bool internalRecordType(Element analyzedElement,
TypeMask newType,
Map<Element, TypeMask> types) {
+ if (compiler.trustTypeAnnotations
+ // Parameters are being checked by the method, and we can
+ // therefore only trust their type after the checks.
+ || (compiler.enableTypeAssertions && !analyzedElement.isParameter())) {
+ var annotation = analyzedElement.computeType(compiler);
+ if (types == returnTypeOf) {
+ assert(annotation is FunctionType);
+ annotation = annotation.returnType;
+ }
+ newType = narrowType(newType, annotation);
+ }
+
// Fields and native methods of native classes are handled
// specially when querying for their type or return type.
if (isNativeElement(analyzedElement)) return false;
@@ -688,9 +706,16 @@
}
TypeMask returnType = returnTypeOf[element];
if (returnType == null) {
- return dynamicType;
+ if ((compiler.trustTypeAnnotations || compiler.enableTypeAssertions)
+ && (element.isFunction()
+ || element.isGetter()
+ || element.isFactoryConstructor())) {
+ FunctionType functionType = element.computeType(compiler);
+ returnType = narrowType(dynamicType, functionType.returnType);
+ } else {
+ returnType = dynamicType;
+ }
}
- assert(returnType != null);
return returnType;
}
@@ -746,16 +771,27 @@
element = element.implementation;
if (isNativeElement(element) && element.isField()) {
var type = typeOf.putIfAbsent(element, () {
- return new TypeMask.subtype(element.computeType(compiler).asRaw());
+ InterfaceType rawType = element.computeType(compiler).asRaw();
+ return rawType.isDynamic ? dynamicType : new TypeMask.subtype(rawType);
});
assert(type != null);
return type;
}
TypeMask type = typeOf[element];
if (type == null) {
- return dynamicType;
+ if ((compiler.trustTypeAnnotations
+ && (element.isField()
+ || element.isParameter()
+ || element.isVariable()))
+ // Parameters are being checked by the method, and we can
+ // therefore only trust their type after the checks.
+ || (compiler.enableTypeAssertions
+ && (element.isField() || element.isVariable()))) {
+ type = narrowType(dynamicType, element.computeType(compiler));
+ } else {
+ type = dynamicType;
+ }
}
- assert(type != null);
return type;
}
@@ -793,6 +829,8 @@
return functionType == null ? dynamicType : functionType;
} else if (element.isField()) {
return typeOfElement(element);
+ } else if (Elements.isUnresolved(element)) {
+ return dynamicType;
} else {
assert(element.isGetter());
return returnTypeOfElement(element);
@@ -1234,7 +1272,6 @@
* [secondType].
*/
TypeMask computeLUB(TypeMask firstType, TypeMask secondType) {
- assert(secondType != null);
if (firstType == null) {
return secondType;
} else if (isDynamicType(secondType)) {
@@ -1254,6 +1291,7 @@
{bool isNullable: true}) {
if (annotation.isDynamic) return type;
if (annotation.isMalformed) return type;
+ if (annotation.isVoid) return nullType;
if (annotation.element == compiler.objectClass) return type;
TypeMask otherType;
if (annotation.kind == TypeKind.TYPEDEF
@@ -1266,6 +1304,7 @@
otherType = new TypeMask.nonNullSubtype(annotation);
}
if (isNullable) otherType = otherType.nullable();
+ if (type == null) return otherType;
return type.intersection(otherType, compiler);
}
}
@@ -1308,21 +1347,27 @@
class LocalsHandler {
final InternalSimpleTypesInferrer inferrer;
final Map<Element, TypeMask> locals;
- final Set<Element> capturedAndBoxed;
+ final Map<Element, Element> capturedAndBoxed;
final Map<Element, TypeMask> fieldsInitializedInConstructor;
final bool inTryBlock;
bool isThisExposed;
bool seenReturn = false;
+ bool seenBreakOrContinue = false;
+
+ bool get aborts {
+ return seenReturn || seenBreakOrContinue;
+ }
LocalsHandler(this.inferrer)
: locals = new Map<Element, TypeMask>(),
- capturedAndBoxed = new Set<Element>(),
+ capturedAndBoxed = new Map<Element, Element>(),
fieldsInitializedInConstructor = new Map<Element, TypeMask>(),
inTryBlock = false,
isThisExposed = true;
LocalsHandler.from(LocalsHandler other, {bool inTryBlock: false})
: locals = new Map<Element, TypeMask>.from(other.locals),
- capturedAndBoxed = new Set<Element>.from(other.capturedAndBoxed),
+ capturedAndBoxed = new Map<Element, Element>.from(
+ other.capturedAndBoxed),
fieldsInitializedInConstructor = new Map<Element, TypeMask>.from(
other.fieldsInitializedInConstructor),
inTryBlock = other.inTryBlock || inTryBlock,
@@ -1330,15 +1375,19 @@
isThisExposed = other.isThisExposed;
TypeMask use(Element local) {
- if (capturedAndBoxed.contains(local)) {
- return inferrer.typeOfElement(local);
+ if (capturedAndBoxed.containsKey(local)) {
+ return inferrer.typeOfElement(capturedAndBoxed[local]);
}
return locals[local];
}
void update(Element local, TypeMask type) {
assert(type != null);
- if (capturedAndBoxed.contains(local) || inTryBlock) {
+ if (inferrer.compiler.trustTypeAnnotations
+ || inferrer.compiler.enableTypeAssertions) {
+ type = inferrer.narrowType(type, local.computeType(inferrer.compiler));
+ }
+ if (capturedAndBoxed.containsKey(local) || inTryBlock) {
// If a local is captured and boxed, or is set in a try block,
// we compute the LUB of its assignments.
//
@@ -1350,22 +1399,23 @@
locals[local] = type;
}
- void setCapturedAndBoxed(Element local) {
- capturedAndBoxed.add(local);
+ void setCapturedAndBoxed(Element local, Element field) {
+ capturedAndBoxed[local] = field;
}
/**
* Merge handlers [first] and [second] into [:this:] and returns
* whether the merge changed one of the variables types in [first].
*/
- bool merge(LocalsHandler other) {
+ bool merge(LocalsHandler other, {bool discardIfAborts: true}) {
bool changed = false;
List<Element> toRemove = <Element>[];
// Iterating over a map and just updating its entries is OK.
locals.forEach((Element local, TypeMask oldType) {
TypeMask otherType = other.locals[local];
+ bool isCaptured = capturedAndBoxed.containsKey(local);
if (otherType == null) {
- if (!capturedAndBoxed.contains(local)) {
+ if (!isCaptured) {
// If [local] is not in the other map and is not captured
// and boxed, we know it is not a
// local we want to keep. For example, in an if/else, we don't
@@ -1375,9 +1425,15 @@
}
return;
}
- TypeMask type = inferrer.computeLUB(oldType, otherType);
- if (type != oldType) changed = true;
- locals[local] = type;
+ if (!isCaptured && aborts && discardIfAborts) {
+ locals[local] = otherType;
+ } else if (!isCaptured && other.aborts && discardIfAborts) {
+ // Don't do anything.
+ } else {
+ TypeMask type = inferrer.computeLUB(oldType, otherType);
+ if (type != oldType) changed = true;
+ locals[local] = type;
+ }
});
// Remove locals that will not be used anymore.
@@ -1388,12 +1444,12 @@
// Update the locals that are captured and boxed. We
// unconditionally add them to [this] because we register the type
// of boxed variables after analyzing all closures.
- other.capturedAndBoxed.forEach((Element element) {
- capturedAndBoxed.add(element);
+ other.capturedAndBoxed.forEach((Element local, Element field) {
+ capturedAndBoxed[local] = field;
// If [element] is not in our [locals], we need to update it.
// Otherwise, we have already computed the LUB of it.
- if (locals[element] == null) {
- locals[element] = other.locals[element];
+ if (locals[local] == null) {
+ locals[local] = other.locals[local];
}
});
@@ -1419,6 +1475,7 @@
});
isThisExposed = isThisExposed || other.isThisExposed;
seenReturn = seenReturn && other.seenReturn;
+ seenBreakOrContinue = seenBreakOrContinue && other.seenBreakOrContinue;
return changed;
}
@@ -1434,6 +1491,10 @@
final Element outermostElement;
final InternalSimpleTypesInferrer inferrer;
final Compiler compiler;
+ final Map<TargetElement, List<LocalsHandler>> breaksFor =
+ new Map<TargetElement, List<LocalsHandler>>();
+ final Map<TargetElement, List<LocalsHandler>> continuesFor =
+ new Map<TargetElement, List<LocalsHandler>>();
LocalsHandler locals;
TypeMask returnType;
@@ -1481,14 +1542,14 @@
// Update the locals that are boxed in [locals]. These locals will
// be handled specially, in that we are computing their LUB at
// each update, and reading them yields the type that was found in a
- // previous analysis ouf [outermostElement].
+ // previous analysis of [outermostElement].
ClosureClassMap closureData =
compiler.closureToClassMapper.computeClosureToClassMapping(
analyzedElement, node, elements);
ClosureScope scopeData = closureData.capturingScopes[node];
if (scopeData != null) {
- scopeData.capturedVariableMapping.forEach((Element variable, _) {
- locals.setCapturedAndBoxed(variable);
+ scopeData.capturedVariableMapping.forEach((variable, field) {
+ locals.setCapturedAndBoxed(variable, field);
});
}
if (analyzedElement.isField()) {
@@ -1586,14 +1647,16 @@
if (analyzedElement == outermostElement) {
bool changed = false;
- locals.capturedAndBoxed.forEach((Element local) {
- if (inferrer.recordType(local, locals.locals[local])) {
+ locals.capturedAndBoxed.forEach((Element local, Element field) {
+ if (inferrer.recordType(field, locals.locals[local])) {
changed = true;
}
});
// TODO(ngeoffray): Re-analyze method if [changed]?
}
compiler.world.registerSideEffects(analyzedElement, sideEffects);
+ assert(breaksFor.isEmpty);
+ assert(continuesFor.isEmpty);
return returnType;
}
@@ -1654,11 +1717,11 @@
// same as [newType].
ClosureClassMap nestedClosureData =
compiler.closureToClassMapper.getMappingForNestedFunction(node);
- nestedClosureData.forEachNonBoxedCapturedVariable((Element variable) {
+ nestedClosureData.forEachNonBoxedCapturedVariable((variable, field) {
// The type may be null for instance contexts (this and type
// parameters), as well as captured argument checks.
if (locals.locals[variable] == null) return;
- inferrer.recordType(variable, locals.locals[variable]);
+ inferrer.recordType(field, locals.locals[variable]);
});
return inferrer.functionType;
@@ -1848,9 +1911,8 @@
ArgumentsTypes operatorArguments = new ArgumentsTypes([rhsType], null);
if (Elements.isStaticOrTopLevelField(element)) {
Element getterElement = elements[node.selector];
- getterType = getterElement.isField()
- ? inferrer.typeOfElement(element)
- : inferrer.returnTypeOfElement(element);
+ getterType =
+ inferrer.typeOfElementWithSelector(getterElement, getterSelector);
handleStaticSend(node, getterSelector, getterElement, null);
newType = handleDynamicSend(
node, operatorSelector, getterType, operatorArguments);
@@ -1955,7 +2017,7 @@
isThisExposed = true;
if (node.isPropertyAccess) {
handleStaticSend(node, selector, element, null);
- return inferrer.typeOfElement(element);
+ return inferrer.typeOfElementWithSelector(element, selector);
} else if (element.isFunction()) {
if (!selector.applies(element, compiler)) return inferrer.dynamicType;
ArgumentsTypes arguments = analyzeArguments(node.arguments);
@@ -2120,7 +2182,7 @@
Selector selector = elements.getSelector(node);
if (Elements.isStaticOrTopLevelField(element)) {
handleStaticSend(node, selector, element, null);
- return inferrer.typeOfElement(element);
+ return inferrer.typeOfElementWithSelector(element, selector);
} else if (Elements.isInstanceSend(node, elements)) {
return visitDynamicSend(node);
} else if (Elements.isStaticOrTopLevelFunction(element)) {
@@ -2314,51 +2376,77 @@
return inferrer.dynamicType;
}
- TypeMask visitWhile(While node) {
+ void setupBreaksAndContinues(TargetElement element) {
+ if (element == null) return;
+ if (element.isContinueTarget) continuesFor[element] = <LocalsHandler>[];
+ if (element.isBreakTarget) breaksFor[element] = <LocalsHandler>[];
+ }
+
+ void clearBreaksAndContinues(TargetElement element) {
+ continuesFor.remove(element);
+ breaksFor.remove(element);
+ }
+
+ void mergeBreaks(TargetElement element) {
+ if (element == null) return;
+ if (!element.isBreakTarget) return;
+ for (LocalsHandler handler in breaksFor[element]) {
+ locals.merge(handler, discardIfAborts: false);
+ }
+ }
+
+ bool mergeContinues(TargetElement element) {
+ if (element == null) return false;
+ if (!element.isContinueTarget) return false;
+ bool changed = false;
+ for (LocalsHandler handler in continuesFor[element]) {
+ changed = locals.merge(handler, discardIfAborts: false) || changed;
+ }
+ return changed;
+ }
+
+ TypeMask handleLoop(Node node, void logic()) {
loopLevel++;
bool changed = false;
+ TargetElement target = elements[node];
+ setupBreaksAndContinues(target);
do {
LocalsHandler saved = new LocalsHandler.from(locals);
+ logic();
+ changed = saved.merge(locals);
+ locals = saved;
+ changed = mergeContinues(target) || changed;
+ } while (changed);
+ loopLevel--;
+ mergeBreaks(target);
+ clearBreaksAndContinues(target);
+ return inferrer.dynamicType;
+ }
+
+ TypeMask visitWhile(While node) {
+ return handleLoop(node, () {
List<Send> tests = handleCondition(node.condition);
updateIsChecks(tests, usePositive: true);
visit(node.body);
- changed = saved.merge(locals);
- locals = saved;
- } while (changed);
- loopLevel--;
- return inferrer.dynamicType;
+ });
}
TypeMask visitDoWhile(DoWhile node) {
- loopLevel++;
- bool changed = false;
- do {
- LocalsHandler saved = new LocalsHandler.from(locals);
+ return handleLoop(node, () {
visit(node.body);
List<Send> tests = handleCondition(node.condition);
updateIsChecks(tests, usePositive: true);
- changed = saved.merge(locals);
- locals = saved;
- } while (changed);
- loopLevel--;
- return inferrer.dynamicType;
+ });
}
TypeMask visitFor(For node) {
- bool changed = false;
visit(node.initializer);
- loopLevel++;
- do {
- LocalsHandler saved = new LocalsHandler.from(locals);
+ return handleLoop(node, () {
List<Send> tests = handleCondition(node.condition);
updateIsChecks(tests, usePositive: true);
visit(node.body);
visit(node.update);
- changed = saved.merge(locals);
- locals = saved;
- } while (changed);
- loopLevel--;
- return inferrer.dynamicType;
+ });
}
TypeMask visitForIn(ForIn node) {
@@ -2380,15 +2468,9 @@
handlePlainAssignment(identifier, variable, selector,
inferrer.dynamicType, inferrer.dynamicType,
node.expression);
- loopLevel++;
- do {
- LocalsHandler saved = new LocalsHandler.from(locals);
+ return handleLoop(node, () {
visit(node.body);
- changed = saved.merge(locals);
- locals = saved;
- } while (changed);
- loopLevel--;
- return inferrer.dynamicType;
+ });
}
TypeMask visitTryStatement(TryStatement node) {
@@ -2434,6 +2516,48 @@
return visit(node.expression);
}
+ TypeMask visitBlock(Block node) {
+ if (node.statements != null) {
+ for (Node statement in node.statements) {
+ visit(statement);
+ if (locals.aborts) break;
+ }
+ }
+ return inferrer.dynamicType;
+ }
+
+ TypeMask visitLabeledStatement(LabeledStatement node) {
+ Statement body = node.statement;
+ if (body is Loop
+ || body is SwitchStatement
+ || Elements.isUnusedLabel(node, elements)) {
+ // Loops and switches handle their own labels.
+ visit(body);
+ return inferrer.dynamicType;
+ }
+
+ TargetElement targetElement = elements[body];
+ setupBreaksAndContinues(targetElement);
+ visit(body);
+ mergeBreaks(targetElement);
+ clearBreaksAndContinues(targetElement);
+ return inferrer.dynamicType;
+ }
+
+ TypeMask visitBreakStatement(BreakStatement node) {
+ TargetElement target = elements[node];
+ breaksFor[target].add(locals);
+ locals.seenBreakOrContinue = true;
+ return inferrer.dynamicType;
+ }
+
+ TypeMask visitContinueStatement(ContinueStatement node) {
+ TargetElement target = elements[node];
+ continuesFor[target].add(locals);
+ locals.seenBreakOrContinue = true;
+ return inferrer.dynamicType;
+ }
+
void internalError(String reason, {Node node}) {
compiler.internalError(reason, node: node);
}
@@ -2441,7 +2565,24 @@
TypeMask visitSwitchStatement(SwitchStatement node) {
visit(node.parenthesizedExpression);
+ setupBreaksAndContinues(elements[node]);
if (Elements.switchStatementHasContinue(node, elements)) {
+ void forEachLabeledCase(void action(TargetElement target)) {
+ for (SwitchCase switchCase in node.cases) {
+ for (Node labelOrCase in switchCase.labelsAndCases) {
+ if (labelOrCase.asLabel() == null) continue;
+ LabelElement labelElement = elements[labelOrCase];
+ if (labelElement != null) {
+ action(labelElement.target);
+ }
+ }
+ }
+ }
+
+ forEachLabeledCase((TargetElement target) {
+ setupBreaksAndContinues(target);
+ });
+
// If the switch statement has a continue, we conservatively
// visit all cases and update [locals] until we have reached a
// fixed point.
@@ -2451,10 +2592,14 @@
for (Node switchCase in node.cases) {
LocalsHandler saved = new LocalsHandler.from(locals);
visit(switchCase);
- changed = saved.merge(locals) || changed;
+ changed = saved.merge(locals, discardIfAborts: false) || changed;
locals = saved;
}
} while (changed);
+
+ forEachLabeledCase((TargetElement target) {
+ clearBreaksAndContinues(target);
+ });
} else {
LocalsHandler saved = new LocalsHandler.from(locals);
// If there is a default case, the current values of the local
@@ -2465,17 +2610,17 @@
: new LocalsHandler.from(locals);
for (Node switchCase in node.cases) {
- locals = saved;
+ locals = new LocalsHandler.from(saved);
visit(switchCase);
if (result == null) {
result = locals;
} else {
- result.merge(locals);
+ result.merge(locals, discardIfAborts: false);
}
}
-
locals = result;
}
+ clearBreaksAndContinues(elements[node]);
return inferrer.dynamicType;
}
}
diff --git a/sdk/lib/_internal/compiler/implementation/types/type_mask.dart b/sdk/lib/_internal/compiler/implementation/types/type_mask.dart
index 47740ea..905021c 100644
--- a/sdk/lib/_internal/compiler/implementation/types/type_mask.dart
+++ b/sdk/lib/_internal/compiler/implementation/types/type_mask.dart
@@ -28,6 +28,10 @@
factory TypeMask.nonNullSubtype(DartType base)
=> new FlatTypeMask.nonNullSubtype(base);
+ factory TypeMask.unionOf(Iterable<TypeMask> masks, Compiler compiler) {
+ return UnionTypeMask.unionOf(masks, compiler);
+ }
+
/**
* Returns a nullable variant of [this] type mask.
*/
@@ -38,9 +42,12 @@
*/
TypeMask nonNullable();
+ TypeMask simplify(Compiler compiler);
+
bool get isEmpty;
bool get isNullable;
bool get isExact;
+ bool get isUnion;
bool containsOnlyInt(Compiler compiler);
bool containsOnlyDouble(Compiler compiler);
@@ -49,6 +56,11 @@
bool containsOnlyBool(Compiler compiler);
bool containsOnlyString(Compiler compiler);
bool containsOnly(ClassElement element);
+
+ /**
+ * Returns whether this type mask is an instance of [cls].
+ */
+ bool satisfies(ClassElement cls, Compiler compiler);
/**
* Returns whether or not this type mask contains the given type.
diff --git a/sdk/lib/_internal/compiler/implementation/types/types.dart b/sdk/lib/_internal/compiler/implementation/types/types.dart
index 34444fd..5813cfe 100644
--- a/sdk/lib/_internal/compiler/implementation/types/types.dart
+++ b/sdk/lib/_internal/compiler/implementation/types/types.dart
@@ -19,6 +19,7 @@
part 'concrete_types_inferrer.dart';
part 'flat_type_mask.dart';
part 'type_mask.dart';
+part 'union_type_mask.dart';
/**
* Common super class for our type inferrers.
@@ -91,6 +92,9 @@
* is for debugging purposes only and can be omitted.
*/
TypeMask best(var type1, var type2, [element]) {
+ // TODO(polux): Handle [UnionTypeMask].
+ if (type1 != null) type1 = type1.simplify(compiler);
+ if (type2 != null) type2 = type2.simplify(compiler);
final result = _best(type1, type2);
// Tests type1 and type2 for equality modulo normalization of native types.
// Only called when DUMP_SURPRISING_RESULTS is true.
diff --git a/sdk/lib/_internal/compiler/implementation/types/union_type_mask.dart b/sdk/lib/_internal/compiler/implementation/types/union_type_mask.dart
new file mode 100644
index 0000000..82865d5
--- /dev/null
+++ b/sdk/lib/_internal/compiler/implementation/types/union_type_mask.dart
@@ -0,0 +1,259 @@
+// 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 types;
+
+class UnionTypeMask implements TypeMask {
+ final Iterable<FlatTypeMask> disjointMasks;
+
+ static const int MAX_UNION_LENGTH = 4;
+
+ UnionTypeMask._(this.disjointMasks);
+
+ static TypeMask unionOf(Iterable<TypeMask> masks, Compiler compiler) {
+ List<FlatTypeMask> disjoint = <FlatTypeMask>[];
+ unionOfHelper(masks, disjoint, compiler);
+ if (disjoint.isEmpty) return new TypeMask.nonNullEmpty();
+ if (disjoint.length > MAX_UNION_LENGTH) return flatten(disjoint, compiler);
+ if (disjoint.length == 1) return disjoint[0];
+ return new UnionTypeMask._(disjoint);
+ }
+
+ static void unionOfHelper(Iterable<TypeMask> masks,
+ List<FlatTypeMask> disjoint,
+ Compiler compiler) {
+ for (TypeMask mask in masks) {
+ if (mask.isUnion) {
+ UnionTypeMask union = mask;
+ unionOfHelper(union.disjointMasks, disjoint, compiler);
+ } else if (mask.isEmpty && !mask.isNullable) {
+ continue;
+ } else {
+ FlatTypeMask flatMask = mask;
+ assert(flatMask.base == null
+ || flatMask.base.element != compiler.dynamicClass);
+ int inListIndex = -1;
+ bool covered = false;
+
+ // Iterate over [disjoint] to find out if one of the mask
+ // already covers [mask].
+ for (int i = 0; i < disjoint.length; i++) {
+ FlatTypeMask current = disjoint[i];
+ if (current == null) continue;
+ TypeMask newMask = mask.union(current, compiler);
+ // If we have found a disjoint union, continue iterating.
+ if (newMask.isUnion) continue;
+ covered = true;
+ // We found a mask that is either equal to [mask] or is a
+ // supertype of [mask].
+ if (current == newMask) break;
+
+ // [mask] is a supertype of [current], replace the [disjoint]
+ // list with [newMask] instead of [current]. Note that
+ // [newMask] may contain different information than [mask],
+ // like nullability.
+ disjoint[i] = newMask;
+ mask = newMask;
+
+ if (inListIndex != -1) {
+ // If the mask was already covered, we remove the previous
+ // place where it was inserted. This new mask subsumes the
+ // previously covered one.
+ disjoint.removeAt(inListIndex);
+ i--;
+ }
+ // Record where the mask was inserted.
+ inListIndex = i;
+ }
+ // If none of the masks in [disjoint] covers [mask], we just
+ // add [mask] to the list.
+ if (!covered) disjoint.add(mask);
+ }
+ }
+ }
+
+ static TypeMask flatten(List<FlatTypeMask> masks, Compiler compiler) {
+ assert(masks.length > 1);
+ // If either type mask is a subtype type mask, we cannot use a
+ // subclass type mask to represent their union.
+ bool useSubclass = masks.every((e) => !e.isSubtype);
+ bool isNullable = masks.any((e) => e.isNullable);
+
+ // Compute the common supertypes of the two types.
+ ClassElement firstElement = masks[0].base.element;
+ ClassElement secondElement = masks[1].base.element;
+ Iterable<ClassElement> candidates =
+ compiler.world.commonSupertypesOf(firstElement, secondElement);
+ bool unseenType = false;
+ for (int i = 2; i < masks.length; i++) {
+ ClassElement element = masks[i].base.element;
+ Set<ClassElement> supertypes = compiler.world.supertypesOf(element);
+ if (supertypes == null) {
+ unseenType = true;
+ break;
+ }
+ candidates = candidates.where((e) => supertypes.contains(e));
+ }
+
+ if (candidates.isEmpty || unseenType) {
+ // TODO(kasperl): Get rid of this check. It can only happen when
+ // at least one of the two base types is 'unseen'.
+ return new TypeMask(compiler.objectClass.rawType,
+ FlatTypeMask.SUBCLASS,
+ isNullable);
+ }
+ // Compute the best candidate and its kind.
+ ClassElement bestElement;
+ int bestKind;
+ int bestSize;
+ for (ClassElement candidate in candidates) {
+ Set<ClassElement> subclasses = useSubclass
+ ? compiler.world.subclassesOf(candidate)
+ : null;
+ int size;
+ int kind;
+ if (subclasses != null
+ && masks.every((t) => subclasses.contains(t.base.element))) {
+ // If both [this] and [other] are subclasses of the supertype,
+ // then we prefer to construct a subclass type mask because it
+ // will always be at least as small as the corresponding
+ // subtype type mask.
+ kind = FlatTypeMask.SUBCLASS;
+ size = subclasses.length;
+ assert(size <= compiler.world.subtypesOf(candidate).length);
+ } else {
+ kind = FlatTypeMask.SUBTYPE;
+ size = compiler.world.subtypesOf(candidate).length;
+ }
+ // Update the best candidate if the new one is better.
+ if (bestElement == null || size < bestSize) {
+ bestElement = candidate;
+ bestSize = size;
+ bestKind = kind;
+ }
+ }
+ if (bestElement == compiler.objectClass) bestKind = FlatTypeMask.SUBCLASS;
+ return new TypeMask(bestElement.computeType(compiler),
+ bestKind,
+ isNullable);
+ }
+
+ TypeMask union(var other, Compiler compiler) {
+ if (!other.isUnion && disjointMasks.contains(other)) return this;
+
+ List<FlatTypeMask> newList =
+ new List<FlatTypeMask>.from(disjointMasks);
+ if (!other.isUnion) {
+ newList.add(other);
+ } else {
+ assert(other is UnionTypeMask);
+ newList.addAll(other.disjointMasks);
+ }
+ return new TypeMask.unionOf(newList, compiler);
+ }
+
+ TypeMask intersection(var other, Compiler compiler) {
+ if (!other.isUnion && disjointMasks.contains(other)) return other;
+
+ List<TypeMask> intersections = <TypeMask>[];
+ for (TypeMask current in disjointMasks) {
+ if (other.isUnion) {
+ for (FlatTypeMask flatOther in other.disjointMasks) {
+ intersections.add(current.intersection(flatOther, compiler));
+ }
+ } else {
+ intersections.add(current.intersection(other, compiler));
+ }
+ }
+ return new TypeMask.unionOf(intersections, compiler);
+ }
+
+ TypeMask nullable() {
+ if (isNullable) return this;
+ List<FlatTypeMask> newList = new List<FlatTypeMask>.from(disjointMasks);
+ newList[0] = newList[0].nullable();
+ return new UnionTypeMask._(newList);
+ }
+
+ TypeMask nonNullable() {
+ if (!isNullable) return this;
+ Iterable<FlatTypeMask> newIterable =
+ disjointMasks.map((e) => e.nonNullable());
+ return new UnionTypeMask._(newIterable);
+ }
+
+ TypeMask simplify(Compiler compiler) => flatten(disjointMasks, compiler);
+
+ bool get isEmpty => false;
+ bool get isNullable => disjointMasks.any((e) => e.isNullable);
+ bool get isExact => false;
+ bool get isUnion => true;
+
+ bool containsOnlyInt(Compiler compiler) => false;
+ bool containsOnlyDouble(Compiler compiler) => false;
+ bool containsOnlyNum(Compiler compiler) {
+ return disjointMasks.every((mask) {
+ return mask.containsOnlyInt(compiler)
+ || mask.containsOnlyDouble(compiler)
+ || mask.containsOnlyNum(compiler);
+ });
+ }
+ bool containsOnlyNull(Compiler compiler) => false;
+ bool containsOnlyBool(Compiler compiler) => false;
+ bool containsOnlyString(Compiler compiler) => false;
+ bool containsOnly(ClassElement element) => false;
+ bool satisfies(ClassElement cls, Compiler compiler) {
+ return disjointMasks.every((mask) => mask.satisfies(cls, compiler));
+ }
+
+ bool contains(DartType type, Compiler compiler) {
+ return disjointMasks.any((e) => e.contains(type, compiler));
+ }
+
+ bool containsAll(Compiler compiler) => false;
+
+ ClassElement singleClass(Compiler compiler) => null;
+
+ Set<ClassElement> containedClasses(Compiler compiler) {
+ Set<ClassElement> set = new Set<ClassElement>();
+ disjointMasks.forEach((e) => set.addAll(e.containedClasses(compiler)));
+ return set;
+ }
+
+ /**
+ * Returns whether a [selector] call will hit a method at runtime,
+ * and not go through [noSuchMethod].
+ */
+ bool willHit(Selector selector, Compiler compiler) {
+ return disjointMasks.every((e) => e.willHit(selector, compiler));
+ }
+
+ bool canHit(Element element, Selector selector, Compiler compiler) {
+ return disjointMasks.any((e) => e.canHit(element, selector, compiler));
+ }
+
+ Element locateSingleElement(Selector selector, Compiler compiler) {
+ Element candidate;
+ for (FlatTypeMask mask in disjointMasks) {
+ Element current = mask.locateSingleElement(selector, compiler);
+ if (current == null) {
+ return null;
+ } else if (candidate == null) {
+ candidate = current;
+ } else if (candidate != current) {
+ return null;
+ }
+ }
+ return candidate;
+ }
+
+ String toString() => 'Union of $disjointMasks';
+
+ bool operator==(other) {
+ if (identical(this, other)) return true;
+ return other is UnionTypeMask
+ && other.disjointMasks.length == disjointMasks.length
+ && other.disjointMasks.every((e) => disjointMasks.contains(e));
+ }
+}
diff --git a/sdk/lib/_internal/compiler/implementation/universe/full_function_set.dart b/sdk/lib/_internal/compiler/implementation/universe/full_function_set.dart
index c8ad568..268fce6 100644
--- a/sdk/lib/_internal/compiler/implementation/universe/full_function_set.dart
+++ b/sdk/lib/_internal/compiler/implementation/universe/full_function_set.dart
@@ -59,7 +59,7 @@
ClassElement single = classes[0];
// Return true if the single class in our list does not have a
// single instantiated subclass.
- Set<ClassElement> subtypes = compiler.world.subtypes[single];
+ Set<ClassElement> subtypes = compiler.world.subtypesOf(single);
return subtypes == null
|| subtypes.every((ClassElement each) => !each.isSubclassOf(single));
}
diff --git a/sdk/lib/_internal/compiler/implementation/warnings.dart b/sdk/lib/_internal/compiler/implementation/warnings.dart
index 7dcebd8..c609c17 100644
--- a/sdk/lib/_internal/compiler/implementation/warnings.dart
+++ b/sdk/lib/_internal/compiler/implementation/warnings.dart
@@ -28,6 +28,10 @@
"no named argument '#{argumentName}' found on method");
static const METHOD_NOT_FOUND = const MessageKind(
'no method named #{memberName} in class #{className}');
+ static const OPERATOR_NOT_FOUND = const MessageKind(
+ 'no operator #{memberName} in class #{className}');
+ static const PROPERTY_NOT_FOUND = const MessageKind(
+ 'no property named #{memberName} in class #{className}');
static const NOT_CALLABLE = const MessageKind(
"'#{elementName}' is not callable");
static const MEMBER_NOT_STATIC = const MessageKind(
@@ -35,6 +39,9 @@
static const NO_INSTANCE_AVAILABLE = const MessageKind(
'#{name} is only available in instance methods');
+ static const THIS_IS_THE_METHOD = const MessageKind(
+ "This is the method declaration.");
+
static const UNREACHABLE_CODE = const MessageKind(
'unreachable code');
static const MISSING_RETURN = const MessageKind(
diff --git a/sdk/lib/_internal/compiler/implementation/world.dart b/sdk/lib/_internal/compiler/implementation/world.dart
index f0bd537..122bd9e 100644
--- a/sdk/lib/_internal/compiler/implementation/world.dart
+++ b/sdk/lib/_internal/compiler/implementation/world.dart
@@ -6,32 +6,54 @@
class World {
final Compiler compiler;
- final Map<ClassElement, Set<MixinApplicationElement>> mixinUses;
- final Map<ClassElement, Set<ClassElement>> typesImplementedBySubclasses;
final FullFunctionSet allFunctions;
final Set<Element> functionsCalledInLoop = new Set<Element>();
final Map<Element, SideEffects> sideEffects = new Map<Element, SideEffects>();
- // We keep track of subtype and subclass relationships in four
- // distinct sets to make class hierarchy analysis faster.
- final Map<ClassElement, Set<ClassElement>> subclasses =
- new Map<ClassElement, Set<ClassElement>>();
- final Map<ClassElement, Set<ClassElement>> superclasses =
- new Map<ClassElement, Set<ClassElement>>();
- final Map<ClassElement, Set<ClassElement>> subtypes =
- new Map<ClassElement, Set<ClassElement>>();
- final Map<ClassElement, Set<ClassElement>> supertypes =
+ final Map<ClassElement, Set<MixinApplicationElement>> mixinUses =
+ new Map<ClassElement, Set<MixinApplicationElement>>();
+
+ final Map<ClassElement, Set<ClassElement>> _typesImplementedBySubclasses =
new Map<ClassElement, Set<ClassElement>>();
+ // We keep track of subtype and subclass relationships in four
+ // distinct sets to make class hierarchy analysis faster.
+ final Map<ClassElement, Set<ClassElement>> _subclasses =
+ new Map<ClassElement, Set<ClassElement>>();
+ final Map<ClassElement, Set<ClassElement>> _superclasses =
+ new Map<ClassElement, Set<ClassElement>>();
+ final Map<ClassElement, Set<ClassElement>> _subtypes =
+ new Map<ClassElement, Set<ClassElement>>();
+ final Map<ClassElement, Set<ClassElement>> _supertypes =
+ new Map<ClassElement, Set<ClassElement>>();
+
+ Set<ClassElement> subclassesOf(ClassElement cls) {
+ return _subclasses[cls.declaration];
+ }
+
+ Set<ClassElement> subtypesOf(ClassElement cls) {
+ return _subtypes[cls.declaration];
+ }
+
+ Set<ClassElement> superclassesOf(ClassElement cls) {
+ return _superclasses[cls.declaration];
+ }
+
+ Set<ClassElement> supertypesOf(ClassElement cls) {
+ return _supertypes[cls.declaration];
+ }
+
+ Set<ClassElement> typesImplementedBySubclassesOf(ClassElement cls) {
+ return _typesImplementedBySubclasses[cls];
+ }
+
World(Compiler compiler)
- : mixinUses = new Map<ClassElement, Set<MixinApplicationElement>>(),
- typesImplementedBySubclasses =
- new Map<ClassElement, Set<ClassElement>>(),
- allFunctions = new FullFunctionSet(compiler),
+ : allFunctions = new FullFunctionSet(compiler),
this.compiler = compiler;
void populate() {
void addSubtypes(ClassElement cls) {
+ assert(cls.isDeclaration);
if (cls.resolutionState != STATE_DONE) {
compiler.internalErrorOnElement(
cls, 'Class "${cls.name.slowToString()}" is not resolved.');
@@ -39,9 +61,9 @@
for (DartType type in cls.allSupertypes) {
Set<Element> supertypesOfClass =
- supertypes.putIfAbsent(cls, () => new Set<ClassElement>());
+ _supertypes.putIfAbsent(cls, () => new Set<ClassElement>());
Set<Element> subtypesOfSupertype =
- subtypes.putIfAbsent(type.element, () => new Set<ClassElement>());
+ _subtypes.putIfAbsent(type.element, () => new Set<ClassElement>());
supertypesOfClass.add(type.element);
subtypesOfSupertype.add(cls);
}
@@ -51,14 +73,14 @@
DartType type = cls.supertype;
while (type != null) {
Set<Element> superclassesOfClass =
- superclasses.putIfAbsent(cls, () => new Set<ClassElement>());
+ _superclasses.putIfAbsent(cls, () => new Set<ClassElement>());
Set<Element> subclassesOfSuperclass =
- subclasses.putIfAbsent(type.element, () => new Set<ClassElement>());
+ _subclasses.putIfAbsent(type.element, () => new Set<ClassElement>());
superclassesOfClass.add(type.element);
subclassesOfSuperclass.add(cls);
Set<Element> typesImplementedBySubclassesOfCls =
- typesImplementedBySubclasses.putIfAbsent(
+ _typesImplementedBySubclasses.putIfAbsent(
type.element, () => new Set<ClassElement>());
for (DartType current in cls.allSupertypes) {
typesImplementedBySubclassesOfCls.add(current.element);
@@ -76,9 +98,9 @@
}
Iterable<ClassElement> commonSupertypesOf(ClassElement x, ClassElement y) {
- Set<ClassElement> xSet = supertypes[x];
+ Set<ClassElement> xSet = supertypesOf(x);
if (xSet == null) return const <ClassElement>[];
- Set<ClassElement> ySet = supertypes[y];
+ Set<ClassElement> ySet = supertypesOf(y);
if (ySet == null) return const <ClassElement>[];
Set<ClassElement> smallSet, largeSet;
if (xSet.length <= ySet.length) {
@@ -93,6 +115,8 @@
void registerMixinUse(MixinApplicationElement mixinApplication,
ClassElement mixin) {
+ // We don't support patch classes as mixin.
+ assert(mixin.isDeclaration);
Set<MixinApplicationElement> users =
mixinUses.putIfAbsent(mixin, () =>
new Set<MixinApplicationElement>());
@@ -105,12 +129,12 @@
}
bool hasAnySubclass(ClassElement cls) {
- Set<ClassElement> classes = subclasses[cls];
+ Set<ClassElement> classes = subclassesOf(cls);
return classes != null && !classes.isEmpty;
}
bool hasAnySubtype(ClassElement cls) {
- Set<ClassElement> classes = subtypes[cls];
+ Set<ClassElement> classes = subtypesOf(cls);
return classes != null && !classes.isEmpty;
}
@@ -124,7 +148,7 @@
// Returns whether a subclass of [superclass] implements [type].
bool hasAnySubclassThatImplements(ClassElement superclass, DartType type) {
- Set<ClassElement> subclasses = typesImplementedBySubclasses[superclass];
+ Set<ClassElement> subclasses = typesImplementedBySubclassesOf(superclass);
if (subclasses == null) return false;
return subclasses.contains(type.element);
}
@@ -182,6 +206,13 @@
}
SideEffects getSideEffectsOfElement(Element element) {
+ // The type inferrer (where the side effects are being computed),
+ // does not see generative constructor bodies because they are
+ // created by the backend. Also, it does not make any distinction
+ // between a constructor and its body for side effects. This
+ // implies that currently, the side effects of a constructor body
+ // contain the side effects of the initializers.
+ assert(!element.isGenerativeConstructorBody());
return sideEffects.putIfAbsent(element.declaration, () {
return new SideEffects();
});
diff --git a/sdk/lib/_internal/compiler/samples/compile_loop/compile_loop.dart b/sdk/lib/_internal/compiler/samples/compile_loop/compile_loop.dart
new file mode 100644
index 0000000..cb0e64b
--- /dev/null
+++ b/sdk/lib/_internal/compiler/samples/compile_loop/compile_loop.dart
@@ -0,0 +1,77 @@
+// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// This sample demonstrates how to run the compiler in a loop reading
+// all sources from memory, instead of using dart:io.
+library sample.compile_loop;
+
+import 'dart:async';
+import 'dart:uri';
+
+import '../../compiler.dart' as compiler;
+
+// If this file is missing, generate it using ../jsonify/jsonify.dart.
+import 'sdk.dart';
+
+Future<String> compile(source) {
+ Future<String> inputProvider(Uri uri) {
+ if (uri.scheme == 'sdk') {
+ var value = SDK_SOURCES['$uri'];
+ if (value == null) {
+ // TODO(ahe): Use new Future.error.
+ throw new Exception('Error: Cannot read: $uri');
+ }
+ return new Future.value(value);
+ } else if ('$uri' == 'memory:/main.dart') {
+ return new Future.value(source);
+ }
+ // TODO(ahe): Use new Future.error.
+ throw new Exception('Error: Cannot read: $uri');
+ }
+ void handler(Uri uri, int begin, int end,
+ String message, compiler.Diagnostic kind) {
+ // TODO(ahe): Remove dart:io import from
+ // ../../implementation/source_file_provider.dart and use
+ // FormattingDiagnosticHandler instead.
+ print({ 'uri': '$uri',
+ 'begin': begin,
+ 'end': end,
+ 'message': message,
+ 'kind': kind.name });
+ if (kind == compiler.Diagnostic.ERROR) {
+ throw new Exception('Unexpected error occurred.');
+ }
+ }
+ return compiler.compile(
+ new Uri('memory:/main.dart'),
+ Uri.parse('sdk:/sdk/'),
+ null,
+ inputProvider,
+ handler,
+ []);
+}
+
+int iterations = 10;
+
+main() {
+ compile(EXAMPLE_HELLO_HTML).then((jsResult) {
+ if (jsResult == null) throw 'Compilation failed';
+ if (--iterations > 0) main();
+ });
+}
+
+const String EXAMPLE_HELLO_HTML = r'''
+// Go ahead and modify this example.
+
+import "dart:html";
+
+var greeting = "Hello, World!";
+
+// Displays a greeting.
+void main() {
+ // This example uses HTML to display the greeting and it will appear
+ // in a nested HTML frame (an iframe).
+ document.body.append(new HeadingElement.h1()..appendText(greeting));
+}
+''';
diff --git a/sdk/lib/_internal/compiler/samples/jsonify/jsonify.dart b/sdk/lib/_internal/compiler/samples/jsonify/jsonify.dart
new file mode 100644
index 0000000..891f505
--- /dev/null
+++ b/sdk/lib/_internal/compiler/samples/jsonify/jsonify.dart
@@ -0,0 +1,99 @@
+// 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:io';
+import 'dart:json';
+import 'dart:uri';
+
+// TODO(ahe): Should be dart:mirrors.
+import '../../implementation/mirrors/mirrors.dart';
+
+import '../../../libraries.dart'
+ show LIBRARIES, LibraryInfo;
+
+import '../../implementation/mirrors/dart2js_mirror.dart'
+ show analyze, BackDoor;
+
+import '../../implementation/filenames.dart';
+import '../../implementation/source_file.dart';
+import '../../implementation/source_file_provider.dart';
+import '../../implementation/util/uri_extras.dart';
+
+const DART2JS = '../../implementation/dart2js.dart';
+const DART2JS_MIRROR = '../../implementation/mirrors/dart2js_mirror.dart';
+const SDK_ROOT = '../../../../../';
+
+bool isPublicDart2jsLibrary(String name) {
+ return !name.startsWith('_') && LIBRARIES[name].isDart2jsLibrary;
+}
+
+var handler;
+RandomAccessFile output;
+Uri outputUri;
+Uri sdkRoot;
+
+main() {
+ mainWithOptions(new Options());
+}
+
+mainWithOptions(Options options) {
+ handler = new FormattingDiagnosticHandler()
+ ..throwOnError = true;
+
+ outputUri =
+ handler.provider.cwd.resolve(nativeToUriPath(options.arguments.first));
+ output = new File(options.arguments.first).openSync(mode: FileMode.WRITE);
+
+ Uri myLocation =
+ handler.provider.cwd.resolve(nativeToUriPath(options.script));
+
+ sdkRoot = myLocation.resolve(SDK_ROOT).resolve('../');
+
+ // Get the names of public dart2js libraries.
+ Iterable<String> names = LIBRARIES.keys.where(isPublicDart2jsLibrary);
+
+ // Turn the names into uris by prepending dart: to them.
+ List<Uri> uris = names.map((String name) => Uri.parse('dart:$name')).toList();
+
+ analyze(uris, myLocation.resolve(SDK_ROOT), null, handler.provider, handler)
+ .then(jsonify);
+}
+
+jsonify(MirrorSystem mirrors) {
+ var map = {};
+
+ mirrors.libraries.forEach((_, LibraryMirror library) {
+ BackDoor.compilationUnitsOf(library).forEach((compilationUnit) {
+ Uri uri = compilationUnit.uri;
+ String filename = relativize(sdkRoot, uri, false);
+ SourceFile file = handler.provider.sourceFiles['$uri'];
+ map['sdk:/$filename'] = file.text;
+ });
+ });
+
+ LIBRARIES.forEach((name, info) {
+ var patch = info.dart2jsPatchPath;
+ if (patch != null) {
+ Uri uri = sdkRoot.resolve('sdk/lib/$patch');
+ String filename = relativize(sdkRoot, uri, false);
+ SourceFile file = handler.provider.sourceFiles['$uri'];
+ map['sdk:/$filename'] = file.text;
+ }
+ });
+
+ output.writeStringSync('''
+// 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.
+
+// DO NOT EDIT.
+// This file is generated by jsonify.dart.
+
+library dart.sdk_sources;
+
+const Map<String, String> SDK_SOURCES = const <String, String>''');
+ output.writeStringSync(stringify(map).replaceAll(r'$', r'\$'));
+ output.writeStringSync(';\n');
+ output.closeSync();
+}
diff --git a/sdk/lib/_internal/pub/lib/src/entrypoint.dart b/sdk/lib/_internal/pub/lib/src/entrypoint.dart
index edfffba..a10a0c1 100644
--- a/sdk/lib/_internal/pub/lib/src/entrypoint.dart
+++ b/sdk/lib/_internal/pub/lib/src/entrypoint.dart
@@ -63,15 +63,17 @@
/// using the `package:` scheme.
///
/// This will automatically install the package to the system-wide cache as
- /// well if it requires network access to retrieve (specifically, if
- /// `id.source.shouldCache` is true).
+ /// well if it requires network access to retrieve (specifically, if the
+ /// package's source has [shouldCache] as `true`).
///
/// See also [installDependencies].
Future<PackageId> install(PackageId id) {
- var pendingOrCompleted = _installs[id];
- if (pendingOrCompleted != null) return pendingOrCompleted;
+ var pending = _installs[id];
+ if (pending != null) return pending;
var packageDir = path.join(packagesDir, id.name);
+ var source;
+
var future = new Future.sync(() {
ensureDir(path.dirname(packageDir));
@@ -82,16 +84,18 @@
deleteEntry(packageDir);
}
- if (id.source.shouldCache) {
+ source = cache.sources[id.source];
+
+ if (source.shouldCache) {
return cache.install(id).then(
(pkg) => createPackageSymlink(id.name, pkg.dir, packageDir));
} else {
- return id.source.install(id, packageDir).then((found) {
+ return source.install(id, packageDir).then((found) {
if (found) return null;
- fail('Package ${id.name} not found in source "${id.source.name}".');
+ fail('Package ${id.name} not found in source "${id.source}".');
});
}
- }).then((_) => id.resolved);
+ }).then((_) => source.resolveId(id));
_installs[id] = future;
diff --git a/sdk/lib/_internal/pub/lib/src/git_source.dart b/sdk/lib/_internal/pub/lib/src/git_source.dart
index c98616d..bccae27 100644
--- a/sdk/lib/_internal/pub/lib/src/git_source.dart
+++ b/sdk/lib/_internal/pub/lib/src/git_source.dart
@@ -112,12 +112,12 @@
return _revisionAt(id).then((revision) {
var description = {'url': _getUrl(id), 'ref': _getRef(id)};
description['resolved-ref'] = revision;
- return new PackageId(id.name, this, id.version, description);
+ return new PackageId(id.name, name, id.version, description);
});
}
// TODO(keertip): Implement getCachedPackages().
-
+
/// Ensure that the canonical clone of the repository referred to by [id] (the
/// one in `<system cache>/git/cache`) exists and is up-to-date. Returns a
/// future that completes once this is finished and throws an exception if it
diff --git a/sdk/lib/_internal/pub/lib/src/hosted_source.dart b/sdk/lib/_internal/pub/lib/src/hosted_source.dart
index 17b1839..62503fe 100644
--- a/sdk/lib/_internal/pub/lib/src/hosted_source.dart
+++ b/sdk/lib/_internal/pub/lib/src/hosted_source.dart
@@ -48,7 +48,7 @@
/// Downloads and parses the pubspec for a specific version of a package that
/// is available from the site.
- Future<Pubspec> describe(PackageId id) {
+ Future<Pubspec> describeUncached(PackageId id) {
// Request it from the server.
var url = _makeVersionUrl(id, (server, package, version) =>
"$server/packages/$package/versions/$version.yaml");
@@ -191,9 +191,9 @@
throw new UnsupportedError("Cannot install packages when offline.");
}
- Future<Pubspec> describe(PackageId id) {
+ Future<Pubspec> describeUncached(PackageId id) {
// [getVersions()] will only return packages that are already cached.
- // SystemCache should only call [describe()] on a package after it has
+ // Source should only call [describeUncached()] on a package after it has
// failed to find it in the cache, so this code should not be reached.
throw new UnsupportedError("Cannot describe packages when offline.");
}
diff --git a/sdk/lib/_internal/pub/lib/src/lock_file.dart b/sdk/lib/_internal/pub/lib/src/lock_file.dart
index 1e85a4d..316e8b5 100644
--- a/sdk/lib/_internal/pub/lib/src/lock_file.dart
+++ b/sdk/lib/_internal/pub/lib/src/lock_file.dart
@@ -58,21 +58,20 @@
throw new FormatException('Package $name is missing a source.');
}
var sourceName = spec['source'];
- if (!sources.contains(sourceName)) {
- throw new FormatException(
- 'Could not find a source named $sourceName.');
- }
- var source = sources[sourceName];
- // Parse the description.
if (!spec.containsKey('description')) {
throw new FormatException('Package $name is missing a description.');
}
var description = spec['description'];
- description = source.parseDescription(filePath, description,
- fromLockFile: true);
- var id = new PackageId(name, source, version, description);
+ // Parse the description if we know the source.
+ if (sources.contains(sourceName)) {
+ var source = sources[sourceName];
+ description = source.parseDescription(filePath, description,
+ fromLockFile: true);
+ }
+
+ var id = new PackageId(name, sourceName, version, description);
// Validate the name.
if (name != id.name) {
@@ -97,7 +96,7 @@
sortedKeys.forEach((name) {
packagesObj[name] = {
'version': packages[name].version.toString(),
- 'source': packages[name].source.name,
+ 'source': packages[name].source,
'description': packages[name].description
};
});
diff --git a/sdk/lib/_internal/pub/lib/src/package.dart b/sdk/lib/_internal/pub/lib/src/package.dart
index 62a2a98..a2a1b12 100644
--- a/sdk/lib/_internal/pub/lib/src/package.dart
+++ b/sdk/lib/_internal/pub/lib/src/package.dart
@@ -10,7 +10,6 @@
import 'io.dart';
import 'pubspec.dart';
-import 'source.dart';
import 'source_registry.dart';
import 'version.dart';
@@ -87,9 +86,9 @@
/// The name of the package being identified.
final String name;
- /// The [Source] used to look up this package given its [description]. If
- /// this is a root package, this will be `null`.
- final Source source;
+ /// The name of the [Source] used to look up this package given its
+ /// [description]. If this is a root package, this will be `null`.
+ final String source;
/// The metadata used by the package's [source] to identify and locate it. It
/// contains whatever [Source]-specific data it needs to be able to install
@@ -100,13 +99,8 @@
/// Whether this package is the root package.
bool get isRoot => source == null;
- /// Gets the directory where this package is or would be found in the
- /// [SystemCache].
- Future<String> get systemCacheDirectory => source.systemCacheDirectory(this);
-
String toString() {
if (isRoot) return "$name (root)";
- if (source.isDefault) return name;
return "$name from $source";
}
@@ -117,16 +111,11 @@
/// Returns a [PackageId] for this package with the given concrete version.
PackageId atVersion(Version version) =>
new PackageId(name, source, version, description);
-
- /// Returns `true` if this package's description matches [other]'s.
- bool descriptionEquals(PackageDep other) {
- return source.descriptionsEqual(description, other.description);
- }
}
/// A reference to a [Package], but not any particular version(s) of it.
class PackageRef extends _PackageName {
- PackageRef(String name, Source source, description)
+ PackageRef(String name, String source, description)
: super(name, source, description);
int get hashCode => name.hashCode ^ source.hashCode;
@@ -138,18 +127,6 @@
other.name == name &&
other.source == source;
}
-
- /// Gets the list of ids of all versions of the package that are described by
- /// this reference.
- Future<List<PackageId>> getVersions() {
- if (isRoot) {
- throw new StateError("Cannot get versions for the root package.");
- }
-
- return source.getVersions(name, description).then((versions) {
- return versions.map((version) => atVersion(version)).toList();
- });
- }
}
/// A reference to a specific version of a package. A package ID contains
@@ -163,7 +140,7 @@
/// The package's version.
final Version version;
- PackageId(String name, Source source, this.version, description)
+ PackageId(String name, String source, this.version, description)
: super(name, source, description);
/// Creates an ID for the given root package.
@@ -184,15 +161,8 @@
String toString() {
if (isRoot) return "$name $version (root)";
- if (source.isDefault) return "$name $version";
return "$name $version from $source";
}
-
- /// Returns the pubspec for this package.
- Future<Pubspec> describe() => source.systemCache.describe(this);
-
- /// Returns a future that completes to the resolved [PackageId] for this id.
- Future<PackageId> get resolved => source.resolveId(this);
}
/// A reference to a constrained range of versions of one package.
@@ -200,7 +170,7 @@
/// The allowed package versions.
final VersionConstraint constraint;
- PackageDep(String name, Source source, this.constraint, description)
+ PackageDep(String name, String source, this.constraint, description)
: super(name, source, description);
String toString() {
diff --git a/sdk/lib/_internal/pub/lib/src/path_source.dart b/sdk/lib/_internal/pub/lib/src/path_source.dart
index 2b66e3b..5972050 100644
--- a/sdk/lib/_internal/pub/lib/src/path_source.dart
+++ b/sdk/lib/_internal/pub/lib/src/path_source.dart
@@ -23,7 +23,7 @@
final name = 'path';
final shouldCache = false;
- Future<Pubspec> describe(PackageId id) {
+ Future<Pubspec> describeUncached(PackageId id) {
return new Future.sync(() {
_validatePath(id.name, id.description);
return new Pubspec.load(id.name, id.description["path"],
diff --git a/sdk/lib/_internal/pub/lib/src/pubspec.dart b/sdk/lib/_internal/pub/lib/src/pubspec.dart
index 69dc880..e01cab1 100644
--- a/sdk/lib/_internal/pub/lib/src/pubspec.dart
+++ b/sdk/lib/_internal/pub/lib/src/pubspec.dart
@@ -214,11 +214,9 @@
}
}
-/**
- * Evaluates whether the given [url] for [field] is valid.
- *
- * Throws [FormatException] on an invalid url.
- */
+/// Evaluates whether the given [url] for [field] is valid.
+///
+/// Throws [FormatException] on an invalid url.
void _validateFieldUrl(url, String field) {
if (url is! String) {
throw new FormatException(
@@ -247,14 +245,16 @@
}
yaml.forEach((name, spec) {
- var description, source;
+ var description;
+ var sourceName;
+
var versionConstraint = new VersionRange();
if (spec == null) {
description = name;
- source = sources.defaultSource;
+ sourceName = sources.defaultSource.name;
} else if (spec is String) {
description = name;
- source = sources.defaultSource;
+ sourceName = sources.defaultSource.name;
versionConstraint = new VersionConstraint.parse(spec);
} else if (spec is Map) {
if (spec.containsKey('version')) {
@@ -267,24 +267,27 @@
'Dependency $name may only have one source: $sourceNames.');
}
- var sourceName = only(sourceNames);
+ sourceName = only(sourceNames);
if (sourceName is! String) {
throw new FormatException(
'Source name $sourceName should be a string.');
}
- source = sources[sourceName];
description = spec[sourceName];
} else {
throw new FormatException(
'Dependency specification $spec should be a string or a mapping.');
}
- description = source.parseDescription(pubspecPath, description,
- fromLockFile: false);
+ // If we have a valid source, use it to process the description. Allow
+ // unknown sources so pub doesn't choke on old pubspecs.
+ if (sources.contains(sourceName)) {
+ description = sources[sourceName].parseDescription(
+ pubspecPath, description, fromLockFile: false);
+ }
dependencies.add(new PackageDep(
- name, source, versionConstraint, description));
+ name, sourceName, versionConstraint, description));
});
return dependencies;
diff --git a/sdk/lib/_internal/pub/lib/src/solver/backtracking_solver.dart b/sdk/lib/_internal/pub/lib/src/solver/backtracking_solver.dart
index 97d35da..1338b63 100644
--- a/sdk/lib/_internal/pub/lib/src/solver/backtracking_solver.dart
+++ b/sdk/lib/_internal/pub/lib/src/solver/backtracking_solver.dart
@@ -387,6 +387,14 @@
// Include dev dependencies of the root package.
if (id.isRoot) deps.addAll(pubspec.devDependencies);
+ // Make sure the package doesn't have any bad dependencies.
+ for (var dep in deps) {
+ if (!dep.isRoot && !_solver.sources.contains(dep.source)) {
+ throw new UnknownSourceException(id.name,
+ [new Dependency(id.name, dep)]);
+ }
+ }
+
// Given a package dep, returns a future that completes to a pair of the
// dep and the number of versions available for it.
getNumVersions(PackageDep dep) {
@@ -433,8 +441,8 @@
});
}
- /// Traverses the references that [depender] depends on, stored in [refs].
- /// Desctructively modifies [refs]. Completes to a list of packages if the
+ /// Traverses the references that [depender] depends on, stored in [deps].
+ /// Desctructively modifies [deps]. Completes to a list of packages if the
/// traversal is complete. Completes it to an error if a failure occurred.
/// Otherwise, recurses.
Future<List<PackageId>> _traverseDeps(String depender,
@@ -465,7 +473,7 @@
}
/// Ensures that dependency [dep] from [depender] is consistent with the
- /// other dependencies on the same package. Throws a [SolverFailure]
+ /// other dependencies on the same package. Throws a [SolveFailure]
/// exception if not. Only validates sources and descriptions, not the
/// version.
void _validateDependency(PackageDep dep, String depender) {
@@ -474,7 +482,7 @@
if (required == null) return;
// Make sure all of the existing sources match the new reference.
- if (required.dep.source.name != dep.source.name) {
+ if (required.dep.source != dep.source) {
_solver.logSolve('source mismatch on ${dep.name}: ${required.dep.source} '
'!= ${dep.source}');
throw new SourceMismatchException(dep.name,
@@ -482,7 +490,8 @@
}
// Make sure all of the existing descriptions match the new reference.
- if (!dep.descriptionEquals(required.dep)) {
+ var source = _solver.sources[dep.source];
+ if (!source.descriptionsEqual(dep.description, required.dep.description)) {
_solver.logSolve('description mismatch on ${dep.name}: '
'${required.dep.description} != ${dep.description}');
throw new DescriptionMismatchException(dep.name,
@@ -492,7 +501,7 @@
/// Adds the version constraint that [depender] places on [dep] to the
/// overall constraint that all shared dependencies place on [dep]. Throws a
- /// [SolverFailure] if that results in an unsolvable constraints.
+ /// [SolveFailure] if that results in an unsolvable constraints.
///
/// Returns the combined [VersionConstraint] that all dependers place on the
/// package.
@@ -517,7 +526,7 @@
/// Validates the currently selected package against the new dependency that
/// [dep] and [constraint] place on it. Returns `null` if there is no
- /// currently selected package, throws a [SolverFailure] if the new reference
+ /// currently selected package, throws a [SolveFailure] if the new reference
/// it not does not allow the previously selected version, or returns the
/// selected package if successful.
PackageId _validateSelected(PackageDep dep, VersionConstraint constraint) {
@@ -538,7 +547,7 @@
/// the solver state so that we can backtrack from this decision if it turns
/// out wrong, but continues traversing with the new selection.
///
- /// Returns a future that completes with a [SolverFailure] if a version
+ /// Returns a future that completes with a [SolveFailure] if a version
/// could not be selected or that completes successfully if a package was
/// selected and traversing should continue.
Future _selectPackage(PackageDep dep, VersionConstraint constraint) {
@@ -608,8 +617,11 @@
var required = _getRequired(name);
if (required != null) {
- if (package.source.name != required.dep.source.name) return null;
- if (!package.descriptionEquals(required.dep)) return null;
+ if (package.source != required.dep.source) return null;
+
+ var source = _solver.sources[package.source];
+ if (!source.descriptionsEqual(
+ package.description, required.dep.description)) return null;
}
return package;
@@ -617,7 +629,7 @@
}
/// Ensures that if [pubspec] has an SDK constraint, then it is compatible
-/// with the current SDK. Throws a [SolverFailure] if not.
+/// with the current SDK. Throws a [SolveFailure] if not.
void _validateSdkConstraint(Pubspec pubspec) {
// If the user is running a continouous build of the SDK, just disable SDK
// constraint checking entirely. The actual version number you get is
diff --git a/sdk/lib/_internal/pub/lib/src/solver/version_solver.dart b/sdk/lib/_internal/pub/lib/src/solver/version_solver.dart
index 885acdc..1ae8d3e 100644
--- a/sdk/lib/_internal/pub/lib/src/solver/version_solver.dart
+++ b/sdk/lib/_internal/pub/lib/src/solver/version_solver.dart
@@ -14,6 +14,7 @@
import '../source.dart';
import '../source_registry.dart';
import '../version.dart';
+import '../utils.dart';
import 'backtracking_solver.dart';
/// Attempts to select the best concrete versions for all of the transitive
@@ -70,7 +71,11 @@
/// Used to avoid requesting the same pubspec from the server repeatedly.
class PubspecCache {
final SourceRegistry _sources;
+
+ /// The already-requested cached version lists.
final _versions = new Map<PackageRef, List<PackageId>>();
+
+ /// The already-requested cached pubspecs.
final _pubspecs = new Map<PackageId, Pubspec>();
/// The number of times a version list was requested and it wasn't cached and
@@ -105,10 +110,9 @@
}
pubspecCacheMisses++;
- return id.describe().then((pubspec) {
- log.solver('requested $id pubspec');
- // Cache it.
+ var source = _sources[id.source];
+ return source.describe(id).then((pubspec) {
_pubspecs[id] = pubspec;
return pubspec;
});
@@ -120,6 +124,10 @@
/// Gets the list of versions for [package] in descending order.
Future<List<PackageId>> getVersions(PackageRef package) {
+ if (package.isRoot) {
+ throw new StateError("Cannot get versions for root package $package.");
+ }
+
// See if we have it cached.
var versions = _versions[package];
if (versions != null) {
@@ -128,11 +136,14 @@
}
versionCacheMisses++;
- return package.getVersions().then((ids) {
- // Sort by descending version so we try newer versions first.
- ids.sort((a, b) => b.version.compareTo(a.version));
- log.solver('requested $package version list');
+ var source = _sources[package.source];
+ return source.getVersions(package.name, package.description)
+ .then((versions) {
+ // Sort by descending version so we try newer versions first.
+ versions.sort((a, b) => b.compareTo(a));
+
+ var ids = versions.map((version) => package.atVersion(version)).toList();
_versions[package] = ids;
return ids;
});
@@ -153,7 +164,7 @@
}
/// Base class for all failures that can occur while trying to resolve versions.
-class SolveFailure implements Exception {
+abstract class SolveFailure implements ApplicationException {
/// The name of the package whose version could not be solved. Will be `null`
/// if the failure is not specific to one package.
final String package;
@@ -270,7 +281,6 @@
/// Exception thrown when two packages with the same name but different sources
/// are depended upon.
class SourceMismatchException extends SolveFailure {
-
SourceMismatchException(String package, Iterable<Dependency> dependencies)
: super(package, dependencies);
@@ -280,6 +290,18 @@
"depends on it from source ${dep.source}";
}
+/// Exception thrown when a dependency on an unknown source name is found.
+class UnknownSourceException extends SolveFailure {
+ UnknownSourceException(String package, Iterable<Dependency> dependencies)
+ : super(package, dependencies);
+
+ String toString() {
+ var dep = only(dependencies);
+ return "Package '${dep.depender}' depends on '${dep.dep.name}' from "
+ "unknown source '${dep.dep.source}'.";
+ }
+}
+
/// Exception thrown when two packages with the same name and source but
/// different descriptions are depended upon.
class DescriptionMismatchException extends SolveFailure {
diff --git a/sdk/lib/_internal/pub/lib/src/source.dart b/sdk/lib/_internal/pub/lib/src/source.dart
index 2486e78..f72f173 100644
--- a/sdk/lib/_internal/pub/lib/src/source.dart
+++ b/sdk/lib/_internal/pub/lib/src/source.dart
@@ -68,20 +68,54 @@
/// By default, this assumes that each description has a single version and
/// uses [describe] to get that version.
Future<List<Version>> getVersions(String name, description) {
- return describe(new PackageId(name, this, Version.none, description))
- .then((pubspec) => [pubspec.version]);
+ var id = new PackageId(name, this.name, Version.none, description);
+ return describeUncached(id).then((pubspec) => [pubspec.version]);
}
/// Loads the (possibly remote) pubspec for the package version identified by
/// [id]. This may be called for packages that have not yet been installed
/// during the version resolution process.
///
+ /// If the package has been installed to the system cache, the cached pubspec
+ /// will be used. Otherwise, it delegates to host-specific lookup behavior.
+ ///
/// For cached sources, by default this uses [installToSystemCache] to get the
/// pubspec. There is no default implementation for non-cached sources; they
/// must implement it manually.
Future<Pubspec> describe(PackageId id) {
+ if (id.isRoot) throw new ArgumentError("Cannot describe the root package.");
+ if (id.source != name) {
+ throw new ArgumentError("Package $id does not use source $name.");
+ }
+
+ // Try to get it from the system cache first.
+ if (shouldCache) {
+ return systemCacheDirectory(id).then((packageDir) {
+ if (!fileExists(path.join(packageDir, "pubspec.yaml"))) {
+ return describeUncached(id);
+ }
+
+ return new Pubspec.load(id.name, packageDir, _systemCache.sources);
+ });
+ }
+
+ // Not cached, so get it from the source.
+ return describeUncached(id);
+ }
+
+ /// Loads the pubspec for the package version identified by [id] which is not
+ /// already in the system cache.
+ ///
+ /// For cached sources, by default this uses [installToSystemCache] to get
+ /// the pubspec. There is no default implementation for non-cached sources;
+ /// they must implement it manually.
+ ///
+ /// This method is effectively protected. Derived classes may override it,
+ /// but external code should not call it. Call [describe()] instead.
+ Future<Pubspec> describeUncached(PackageId id) {
if (!shouldCache) {
- throw new UnimplementedError("Source $name must implement describe(id).");
+ throw new UnimplementedError(
+ "Source $name must implement describeUncached(id).");
}
return installToSystemCache(id).then((package) => package.pubspec);
}
diff --git a/sdk/lib/_internal/pub/lib/src/system_cache.dart b/sdk/lib/_internal/pub/lib/src/system_cache.dart
index 567803b..63de5dc 100644
--- a/sdk/lib/_internal/pub/lib/src/system_cache.dart
+++ b/sdk/lib/_internal/pub/lib/src/system_cache.dart
@@ -70,41 +70,25 @@
sources.register(source);
}
- /// Gets the package identified by [id]. If the package is already cached,
- /// reads it from the cache. Otherwise, requests it from the source.
- Future<Pubspec> describe(PackageId id) {
- if (id.isRoot) throw new ArgumentError("Cannot describe the root package.");
-
- // Try to get it from the system cache first.
- if (id.source.shouldCache) {
- return id.systemCacheDirectory.then((packageDir) {
- if (!fileExists(path.join(packageDir, "pubspec.yaml"))) {
- return id.source.describe(id);
- }
-
- return new Pubspec.load(id.name, packageDir, sources);
- });
- }
-
- // Not cached, so get it from the source.
- return id.source.describe(id);
- }
-
/// Ensures that the package identified by [id] is installed to the cache,
/// loads it, and returns it.
///
- /// It is an error to try installing a package from a source with `shouldCache
- /// == false` to the system cache.
+ /// It is an error to try installing a package from a source with
+ /// `shouldCache == false` to the system cache.
Future<Package> install(PackageId id) {
- if (!id.source.shouldCache) {
+ var source = sources[id.source];
+
+ if (!source.shouldCache) {
throw new ArgumentError("Package $id is not cacheable.");
}
var pending = _pendingInstalls[id];
if (pending != null) return pending;
- var future = id.source.installToSystemCache(id)
- .whenComplete(() { _pendingInstalls.remove(id); });
+ var future = source.installToSystemCache(id).whenComplete(() {
+ _pendingInstalls.remove(id);
+ });
+
_pendingInstalls[id] = future;
return future;
}
diff --git a/sdk/lib/_internal/pub/lib/src/validator/dependency.dart b/sdk/lib/_internal/pub/lib/src/validator/dependency.dart
index c147f7b..a1a8f99 100644
--- a/sdk/lib/_internal/pub/lib/src/validator/dependency.dart
+++ b/sdk/lib/_internal/pub/lib/src/validator/dependency.dart
@@ -22,7 +22,7 @@
Future validate() {
return Future.forEach(entrypoint.root.pubspec.dependencies, (dependency) {
- if (dependency.source is! HostedSource) {
+ if (dependency.source != "hosted") {
return _warnAboutSource(dependency);
}
@@ -59,11 +59,11 @@
// Path sources are errors. Other sources are just warnings.
var messages = warnings;
- if (dep.source is PathSource) {
+ if (dep.source == "path") {
messages = errors;
}
- messages.add('Don\'t depend on "${dep.name}" from the ${dep.source.name} '
+ messages.add('Don\'t depend on "${dep.name}" from the ${dep.source} '
'source. Use the hosted source instead. For example:\n'
'\n'
'dependencies:\n'
diff --git a/sdk/lib/_internal/pub/lib/src/validator/license.dart b/sdk/lib/_internal/pub/lib/src/validator/license.dart
index 50d1bfe..16b202f 100644
--- a/sdk/lib/_internal/pub/lib/src/validator/license.dart
+++ b/sdk/lib/_internal/pub/lib/src/validator/license.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.
-library pubspec_field_validator;
+library license_validator;
import 'dart:async';
diff --git a/sdk/lib/_internal/pub/test/install/unknown_source_test.dart b/sdk/lib/_internal/pub/test/install/unknown_source_test.dart
new file mode 100644
index 0000000..e8250c5
--- /dev/null
+++ b/sdk/lib/_internal/pub/test/install/unknown_source_test.dart
@@ -0,0 +1,80 @@
+// Copyright (c) 2012, 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 d.file.
+
+library pub_tests;
+
+import 'dart:io';
+import 'dart:json' as json;
+
+import '../descriptor.dart' as d;
+import '../test_pub.dart';
+
+main() {
+ initConfig();
+ integration('fails gracefully on a dependency from an unknown source', () {
+ d.appDir([{"bad": "foo"}]).create();
+
+ schedulePub(args: ['install'],
+ error: new RegExp("Package 'myapp' depends on 'foo' from unknown "
+ "source 'bad'.\$"),
+ exitCode: 1);
+ });
+
+ integration('fails gracefully on transitive dependency from an unknown '
+ 'source', () {
+ d.dir('foo', [
+ d.libDir('foo', 'foo 0.0.1'),
+ d.libPubspec('foo', '0.0.1', deps: [{"bad": "bar"}])
+ ]).create();
+
+ d.appDir([{"path": "../foo"}]).create();
+
+ schedulePub(args: ['install'],
+ error: new RegExp("Package 'foo' depends on 'bar' from unknown "
+ "source 'bad'.\$"),
+ exitCode: 1);
+ });
+
+ integration('ignores unknown source in lockfile', () {
+ d.dir('foo', [
+ d.libDir('foo'),
+ d.libPubspec('foo', '0.0.1')
+ ]).create();
+
+ // Depend on "foo" from a valid source.
+ d.dir(appPath, [
+ d.pubspec({
+ "name": "myapp",
+ "dependencies": {
+ "foo": {"path": "../foo"}
+ }
+ })
+ ]).create();
+
+ // But lock it to a bad one.
+ d.dir(appPath, [
+ d.file("pubspec.lock", json.stringify({
+ 'packages': {
+ 'foo': {
+ 'version': '0.0.0',
+ 'source': 'bad',
+ 'description': {
+ 'name': 'foo'
+ }
+ }
+ }
+ }))
+ ]).create();
+
+ schedulePub(args: ['install'],
+ output: new RegExp(r"Dependencies installed!$"));
+
+ // Should update to the new one.
+ d.dir(packagesPath, [
+ d.dir("foo", [
+ d.file("foo.dart", 'main() => "foo";')
+ ])
+ ]).validate();
+ });
+}
diff --git a/sdk/lib/_internal/pub/test/lock_file_test.dart b/sdk/lib/_internal/pub/test/lock_file_test.dart
index 0f7fe53..8b05d9d 100644
--- a/sdk/lib/_internal/pub/test/lock_file_test.dart
+++ b/sdk/lib/_internal/pub/test/lock_file_test.dart
@@ -13,6 +13,7 @@
import '../lib/src/source_registry.dart';
import '../lib/src/utils.dart';
import '../lib/src/version.dart';
+import 'test_pub.dart';
class MockSource extends Source {
final String name = 'mock';
@@ -31,6 +32,8 @@
}
main() {
+ initConfig();
+
var sources = new SourceRegistry();
var mockSource = new MockSource();
sources.register(mockSource);
@@ -65,16 +68,28 @@
var bar = lockFile.packages['bar'];
expect(bar.name, equals('bar'));
expect(bar.version, equals(new Version(1, 2, 3)));
- expect(bar.source, equals(mockSource));
+ expect(bar.source, equals(mockSource.name));
expect(bar.description, equals('bar desc'));
var foo = lockFile.packages['foo'];
expect(foo.name, equals('foo'));
expect(foo.version, equals(new Version(2, 3, 4)));
- expect(foo.source, equals(mockSource));
+ expect(foo.source, equals(mockSource.name));
expect(foo.description, equals('foo desc'));
});
+ test("allows an unknown source", () {
+ var lockFile = new LockFile.parse('''
+packages:
+ foo:
+ source: bad
+ version: 1.2.3
+ description: foo desc
+''', sources);
+ var foo = lockFile.packages['foo'];
+ expect(foo.source, equals('bad'));
+ });
+
test("throws if the version is missing", () {
expect(() {
new LockFile.parse('''
@@ -109,18 +124,6 @@
}, throwsFormatException);
});
- test("throws if the source is unknown", () {
- expect(() {
- new LockFile.parse('''
-packages:
- foo:
- version: 1.2.3
- source: notreal
- description: foo desc
-''', sources);
- }, throwsFormatException);
- });
-
test("throws if the description is missing", () {
expect(() {
new LockFile.parse('''
@@ -166,9 +169,9 @@
test('dumps the lockfile to YAML', () {
lockfile.packages['foo'] = new PackageId(
- 'foo', mockSource, new Version.parse('1.2.3'), 'foo desc');
+ 'foo', mockSource.name, new Version.parse('1.2.3'), 'foo desc');
lockfile.packages['bar'] = new PackageId(
- 'bar', mockSource, new Version.parse('3.2.1'), 'bar desc');
+ 'bar', mockSource.name, new Version.parse('3.2.1'), 'bar desc');
expect(loadYaml(lockfile.serialize()), equals({
'packages': {
@@ -189,7 +192,7 @@
test('lockfile is alphabetized by package name', () {
var testNames = ['baz', 'Qwe', 'Q', 'B', 'Bar', 'bar', 'foo'];
testNames.forEach((name) {
- lockfile.packages[name] = new PackageId(name, mockSource,
+ lockfile.packages[name] = new PackageId(name, mockSource.name,
new Version.parse('5.5.5'), '$name desc');
});
diff --git a/sdk/lib/_internal/pub/test/pub_cache_test.dart b/sdk/lib/_internal/pub/test/pub_cache_test.dart
index 6166514..cb38da7 100644
--- a/sdk/lib/_internal/pub/test/pub_cache_test.dart
+++ b/sdk/lib/_internal/pub/test/pub_cache_test.dart
@@ -15,9 +15,9 @@
main() {
initConfig();
-
+
integration('running pub cache displays error message', () {
- schedulePub(args: ['cache'],
+ schedulePub(args: ['cache'],
output: '''
Inspect the system cache.
@@ -26,9 +26,9 @@
error: 'The cache command expects one argument.',
exitCode: 64);
});
-
+
integration('running pub cache foo displays error message', () {
- schedulePub(args: ['cache' ,'foo'],
+ schedulePub(args: ['cache' ,'foo'],
output: '''
Inspect the system cache.
@@ -37,12 +37,12 @@
error: 'Unknown cache command "foo".',
exitCode: 64);
});
-
- integration('running pub cache list when there is no cache', () {
+
+ integration('running pub cache list when there is no cache', () {
schedulePub(args: ['cache', 'list'], output: '{"packages":{}}');
});
-
- integration('running pub cache list on empty cache', () {
+
+ integration('running pub cache list on empty cache', () {
// Set up a cache.
d.dir(cachePath, [
d.dir('hosted', [
@@ -50,10 +50,10 @@
])
])
]).create();
-
+
schedulePub(args: ['cache', 'list'], output: '{"packages":{}}');
});
-
+
integration('running pub cache list', () {
// Set up a cache.
d.dir(cachePath, [
@@ -69,11 +69,28 @@
])
])
]).create();
-
- schedulePub(args: ['cache', 'list'], output:
+
+ schedulePub(args: ['cache', 'list'], output:
new RegExp(r'\{"packages":\{"bar":\{"version":"2\.0\.0","location":'
r'"[^"]+bar-2\.0\.0"\},"foo":\{"version":"1\.2\.3","location":'
r'"[^"]+foo-1\.2\.3"\}\}\}$'));
});
-
+
+ integration('includes packages containing deps with bad sources', () {
+ // Set up a cache.
+ d.dir(cachePath, [
+ d.dir('hosted', [
+ d.dir('pub.dartlang.org', [
+ d.dir("foo-1.2.3", [
+ d.libPubspec("foo", "1.2.3", deps: [{"bad": "bar"}]),
+ d.libDir("foo")
+ ])
+ ])
+ ])
+ ]).create();
+
+ schedulePub(args: ['cache', 'list'], output:
+ new RegExp(r'\{"packages":\{"foo":\{"version":"1\.2\.3","location":'
+ r'"[^"]+foo-1\.2\.3"\}\}\}$'));
+ });
}
\ No newline at end of file
diff --git a/sdk/lib/_internal/pub/test/pubspec_test.dart b/sdk/lib/_internal/pub/test/pubspec_test.dart
index 19f62d4..45413db 100644
--- a/sdk/lib/_internal/pub/test/pubspec_test.dart
+++ b/sdk/lib/_internal/pub/test/pubspec_test.dart
@@ -81,6 +81,18 @@
expect(pubspec.devDependencies, isEmpty);
});
+ test("allows an unknown source", () {
+ var pubspec = new Pubspec.parse(null, '''
+dependencies:
+ foo:
+ unknown: blah
+''', sources);
+
+ var foo = pubspec.dependencies[0];
+ expect(foo.name, equals('foo'));
+ expect(foo.source, equals('unknown'));
+ });
+
test("throws if a package is in dependencies and dev_dependencies", () {
expectFormatError('''
dependencies:
diff --git a/sdk/lib/_internal/pub/test/test_pub.dart b/sdk/lib/_internal/pub/test/test_pub.dart
index 8d417ed..37bf6d0 100644
--- a/sdk/lib/_internal/pub/test/test_pub.dart
+++ b/sdk/lib/_internal/pub/test/test_pub.dart
@@ -545,20 +545,6 @@
for (var dependency in resolvedDependencies) {
var keys = dependency.keys.where((key) => key != "version");
var sourceName = only(keys);
- var source;
- switch (sourceName) {
- case "git":
- source = new GitSource();
- break;
- case "hosted":
- source = new HostedSource();
- break;
- case "path":
- source = new PathSource();
- break;
- default:
- throw new Exception('Unknown source "$sourceName"');
- }
result[_packageName(sourceName, dependency[sourceName])] = dependency;
}
diff --git a/sdk/lib/_internal/pub/test/update/unknown_source_test.dart b/sdk/lib/_internal/pub/test/update/unknown_source_test.dart
new file mode 100644
index 0000000..92dfe1f
--- /dev/null
+++ b/sdk/lib/_internal/pub/test/update/unknown_source_test.dart
@@ -0,0 +1,80 @@
+// Copyright (c) 2012, 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 d.file.
+
+library pub_tests;
+
+import 'dart:io';
+import 'dart:json' as json;
+
+import '../descriptor.dart' as d;
+import '../test_pub.dart';
+
+main() {
+ initConfig();
+ integration('fails gracefully on a dependency from an unknown source', () {
+ d.appDir([{"bad": "foo"}]).create();
+
+ schedulePub(args: ['update'],
+ error: new RegExp("Package 'myapp' depends on 'foo' from unknown "
+ "source 'bad'.\$"),
+ exitCode: 1);
+ });
+
+ integration('fails gracefully on transitive dependency from an unknown '
+ 'source', () {
+ d.dir('foo', [
+ d.libDir('foo', 'foo 0.0.1'),
+ d.libPubspec('foo', '0.0.1', deps: [{"bad": "bar"}])
+ ]).create();
+
+ d.appDir([{"path": "../foo"}]).create();
+
+ schedulePub(args: ['update'],
+ error: new RegExp("Package 'foo' depends on 'bar' from unknown "
+ "source 'bad'.\$"),
+ exitCode: 1);
+ });
+
+ integration('ignores unknown source in lockfile', () {
+ d.dir('foo', [
+ d.libDir('foo'),
+ d.libPubspec('foo', '0.0.1')
+ ]).create();
+
+ // Depend on "foo" from a valid source.
+ d.dir(appPath, [
+ d.pubspec({
+ "name": "myapp",
+ "dependencies": {
+ "foo": {"path": "../foo"}
+ }
+ })
+ ]).create();
+
+ // But lock it to a bad one.
+ d.dir(appPath, [
+ d.file("pubspec.lock", json.stringify({
+ 'packages': {
+ 'foo': {
+ 'version': '0.0.0',
+ 'source': 'bad',
+ 'description': {
+ 'name': 'foo'
+ }
+ }
+ }
+ }))
+ ]).create();
+
+ schedulePub(args: ['update'],
+ output: new RegExp(r"Dependencies updated!$"));
+
+ // Should update to the new one.
+ d.dir(packagesPath, [
+ d.dir("foo", [
+ d.file("foo.dart", 'main() => "foo";')
+ ])
+ ]).validate();
+ });
+}
diff --git a/sdk/lib/_internal/pub/test/version_solver_test.dart b/sdk/lib/_internal/pub/test/version_solver_test.dart
index 35af3ac..47d7198 100644
--- a/sdk/lib/_internal/pub/test/version_solver_test.dart
+++ b/sdk/lib/_internal/pub/test/version_solver_test.dart
@@ -40,6 +40,7 @@
group('root dependency', rootDependency);
group('dev dependency', devDependency);
group('unsolvable', unsolvable);
+ group('bad source', badSource);
group('backtracking', backtracking);
group('SDK constraint', sdkConstraint);
}
@@ -404,6 +405,55 @@
}, error: couldNotSolve, maxTries: 4);
}
+badSource() {
+ testResolve('fail if the root package has a bad source in dep', {
+ 'myapp 0.0.0': {
+ 'foo from bad': 'any'
+ },
+ }, error: unknownSource('myapp', 'foo', 'bad'));
+
+ testResolve('fail if the root package has a bad source in dev dep', {
+ 'myapp 0.0.0': {
+ '(dev) foo from bad': 'any'
+ },
+ }, error: unknownSource('myapp', 'foo', 'bad'));
+
+ testResolve('fail if all versions have bad source in dep', {
+ 'myapp 0.0.0': {
+ 'foo': 'any'
+ },
+ 'foo 1.0.0': {
+ 'bar from bad': 'any'
+ },
+ 'foo 1.0.1': {
+ 'baz from bad': 'any'
+ },
+ 'foo 1.0.3': {
+ 'bang from bad': 'any'
+ },
+ }, error: unknownSource('foo', 'bar', 'bad'), maxTries: 3);
+
+ testResolve('ignore versions with bad source in dep', {
+ 'myapp 1.0.0': {
+ 'foo': 'any'
+ },
+ 'foo 1.0.0': {
+ 'bar': 'any'
+ },
+ 'foo 1.0.1': {
+ 'bar from bad': 'any'
+ },
+ 'foo 1.0.3': {
+ 'bar from bad': 'any'
+ },
+ 'bar 1.0.0': {}
+ }, result: {
+ 'myapp from root': '1.0.0',
+ 'foo': '1.0.0',
+ 'bar': '1.0.0'
+ }, maxTries: 3);
+}
+
backtracking() {
testResolve('circular dependency on older version', {
'myapp 0.0.0': {
@@ -775,7 +825,7 @@
// remote server.
root = package;
} else {
- source.addPackage(name, package);
+ cache.sources[source].addPackage(name, package);
}
});
});
@@ -797,7 +847,7 @@
lockfile.forEach((name, version) {
version = new Version.parse(version);
realLockFile.packages[name] =
- new PackageId(name, source1, version, name);
+ new PackageId(name, source1.name, version, name);
});
}
@@ -856,6 +906,11 @@
SourceMismatchException);
}
+unknownSource(String depender, String dependency, String source) {
+ return (maxTries) => new SolveFailMatcher([depender, dependency, source],
+ maxTries, UnknownSourceException);
+}
+
class SolveSuccessMatcher implements Matcher {
/// The expected concrete package selections.
final Map<String, PackageId> _expected;
@@ -877,7 +932,7 @@
MatchState state, bool verbose) {
if (!result.succeeded) {
description.add('Solver failed with:\n${result.error}');
- return;
+ return null;
}
description.add('Resolved:\n${_listPackages(result.packages)}\n');
@@ -1033,6 +1088,7 @@
throw new Exception('MockSource does not have a package matching '
'"$description".');
}
+
return _packages[description].keys.toList();
});
}
@@ -1098,7 +1154,7 @@
}
void parseSource(String description,
- callback(bool isDev, String name, Source source)) {
+ callback(bool isDev, String name, String source)) {
var isDev = false;
if (description.startsWith("(dev) ")) {
@@ -1107,18 +1163,12 @@
}
var name = description;
- var source = source1;
-
- var sourceNames = {
- 'mock1': source1,
- 'mock2': source2,
- 'root': null
- };
-
+ var source = "mock1";
var match = new RegExp(r"(.*) from (.*)").firstMatch(description);
if (match != null) {
name = match[1];
- source = sourceNames[match[2]];
+ source = match[2];
+ if (source == "root") source = null;
}
callback(isDev, name, source);
diff --git a/sdk/lib/async/stream_controller.dart b/sdk/lib/async/stream_controller.dart
index 3e7dbdc..6ff3ee2 100644
--- a/sdk/lib/async/stream_controller.dart
+++ b/sdk/lib/async/stream_controller.dart
@@ -50,11 +50,6 @@
final _StreamImpl<T> stream;
/**
- *
- * If the stream is canceled before the controller needs new data the
- * [onResume] call might not be executed.
- : stream = new _MultiControllerStream<T>(
- onListen, onPause, onResume, onCancel);
* A controller with a [stream] that supports only one single subscriber.
*
* The controller will buffer all incoming events until the subscriber is
diff --git a/sdk/lib/core/iterable.dart b/sdk/lib/core/iterable.dart
index 9a0bf6f..ef6239a 100644
--- a/sdk/lib/core/iterable.dart
+++ b/sdk/lib/core/iterable.dart
@@ -39,7 +39,7 @@
Iterator<E> get iterator;
/**
- * Returns a lazy [Iterable] where each element [:e:] of [this] is replaced
+ * Returns a lazy [Iterable] where each element [:e:] of `this` is replaced
* by the result of [:f(e):].
*
* This method returns a view of the mapped elements. As long as the
@@ -112,7 +112,7 @@
/**
* Returns true if every elements of this collection satisify the
- * predicate [f]. Returns false otherwise.
+ * predicate [f]. Returns `false` otherwise.
*/
bool every(bool f(E element));
@@ -164,7 +164,7 @@
/**
* Returns an [Iterable] with at most [n] elements.
*
- * The returned [Iterable] may contain fewer than [n] elements, if [this]
+ * The returned [Iterable] may contain fewer than [n] elements, if `this`
* contains fewer than [n] elements.
*/
Iterable<E> take(int n);
@@ -173,9 +173,10 @@
* Returns an [Iterable] that stops once [test] is not satisfied anymore.
*
* The filtering happens lazily. Every new [Iterator] of the returned
- * [Iterable] will start iterating over the elements of [this].
- * When the iterator encounters an element [:e:] that does not satisfy [test],
- * it discards [:e:] and moves into the finished state. That is, it will not
+ * [Iterable] will start iterating over the elements of `this`.
+ *
+ * When the iterator encounters an element `e` that does not satisfy [test],
+ * it discards `e` and moves into the finished state. That is, it will not
* ask or provide any more elements.
*/
Iterable<E> takeWhile(bool test(E value));
@@ -183,7 +184,7 @@
/**
* Returns an [Iterable] that skips the first [n] elements.
*
- * If [this] has fewer than [n] elements, then the resulting [Iterable] will
+ * If `this` has fewer than [n] elements, then the resulting [Iterable] will
* be empty.
*/
Iterable<E> skip(int n);
@@ -192,17 +193,20 @@
* Returns an [Iterable] that skips elements while [test] is satisfied.
*
* The filtering happens lazily. Every new [Iterator] of the returned
- * [Iterable] will iterate over all elements of [this].
+ * [Iterable] will iterate over all elements of `this`.
+ *
* As long as the iterator's elements do not satisfy [test] they are
* discarded. Once an element satisfies the [test] the iterator stops testing
- * and uses every element unconditionally.
+ * and uses every element unconditionally. That is, the elements of the
+ * returned [Iterable] are the elements of `this` starting from the first
+ * element that doesn't satisfy [test].
*/
Iterable<E> skipWhile(bool test(E value));
/**
* Returns the first element.
*
- * If [this] is empty throws a [StateError]. Otherwise this method is
+ * If `this` is empty throws a [StateError]. Otherwise this method is
* equivalent to [:this.elementAt(0):]
*/
E get first;
@@ -210,14 +214,14 @@
/**
* Returns the last element.
*
- * If [this] is empty throws a [StateError].
+ * If `this` is empty throws a [StateError].
*/
E get last;
/**
- * Returns the single element in [this].
+ * Returns the single element in `this`.
*
- * If [this] is empty or has more than one element throws a [StateError].
+ * If `this` is empty or has more than one element throws a [StateError].
*/
E get single;
@@ -234,7 +238,7 @@
* Returns the last element that satisfies the given predicate [f].
*
* If none matches, the result of invoking the [orElse] function is
- * returned. By default, when [orElse] is [:null:], a [StateError] is
+ * returned. By default, when [orElse] is `null`, a [StateError] is
* thrown.
*/
E lastWhere(bool test(E value), {E orElse()});
@@ -248,12 +252,11 @@
/**
* Returns the [index]th element.
*
- * If [this] [Iterable] has fewer than [index] elements throws a
- * [RangeError].
+ * If `this` has fewer than [index] elements throws a [RangeError].
*
- * Note: if [this] does not have a deterministic iteration order then the
+ * Note: if `this` does not have a deterministic iteration order then the
* function may simply return any element without any iteration if there are
- * at least [index] elements in [this].
+ * at least [index] elements in `this`.
*/
E elementAt(int index);
}
diff --git a/sdk/lib/core/list.dart b/sdk/lib/core/list.dart
index 59a1563..672c8b8 100644
--- a/sdk/lib/core/list.dart
+++ b/sdk/lib/core/list.dart
@@ -21,18 +21,18 @@
*
* Example:
*
- * var fixedLengthList = new List(5);
- * fixedLengthList.length = 0; // throws.
- * fixedLengthList.add(499); // throws
- * fixedLengthList[0] = 87;
- * var growableList = [1, 2];
- * growableList.length = 0;
- * growableList.add(499);
- * growableList[0] = 87;
- * var unmodifiableList = const [1, 2];
- * unmodifiableList.length = 0; // throws.
- * unmodifiableList.add(499); // throws
- * unmodifiableList[0] = 87; // throws.
+ * var fixedLengthList = new List(5);
+ * fixedLengthList.length = 0; // throws.
+ * fixedLengthList.add(499); // throws
+ * fixedLengthList[0] = 87;
+ * var growableList = [1, 2];
+ * growableList.length = 0;
+ * growableList.add(499);
+ * growableList[0] = 87;
+ * var unmodifiableList = const [1, 2];
+ * unmodifiableList.length = 0; // throws.
+ * unmodifiableList.add(499); // throws
+ * unmodifiableList[0] = 87; // throws.
*
* Lists are [Iterable].
* List iteration iterates over values in index order.
@@ -94,7 +94,7 @@
* for each index in the range `0` .. `[length] - 1`
* in increasing order.
*
- * The created length's length is fixed unless [growable] is true.
+ * The created list's length is fixed unless [growable] is true.
*/
factory List.generate(int length, E generator(int index),
{ bool growable: true }) {
@@ -118,6 +118,7 @@
/**
* Sets the entry at the given [index] in the list to [value].
+ *
* Throws an [RangeError] if [index] is out of bounds.
*/
void operator []=(int index, E value);
@@ -131,20 +132,23 @@
/**
* Changes the length of the list. If [newLength] is greater than
- * the current [length], entries are initialized to [:null:]. Throws
- * an [UnsupportedError] if the list is not extendable.
+ * the current [length], entries are initialized to [:null:].
+ *
+ * Throws an [UnsupportedError] if the list is not extendable.
*/
void set length(int newLength);
/**
* Adds [value] at the end of the list, extending the length by
- * one. Throws an [UnsupportedError] if the list is not
- * extendable.
+ * one.
+ *
+ * Throws an [UnsupportedError] if the list is not extendable.
*/
void add(E value);
/**
* Appends all elements of the [iterable] to the end of this list.
+ *
* Extends the length of the list by the number of elements in [iterable].
* Throws an [UnsupportedError] if this list is not extensible.
*/
@@ -159,6 +163,7 @@
* Sorts the list according to the order specified by the [compare] function.
*
* The [compare] function must act as a [Comparator].
+ *
* The default [List] implementations use [Comparable.compare] if
* [compare] is omitted.
*/
@@ -178,9 +183,12 @@
* Returns the last index of [element] in the list.
*
* Searches the list backwards from index [start] (inclusive) to 0.
+ *
* The first time an element [:e:] is encountered so that [:e == element:],
* the index of [:e:] is returned.
- * If start is not provided, it defaults to [:this.length - 1:] .
+ *
+ * If start is not provided, it defaults to [:this.length - 1:].
+ *
* Returns -1 if [element] is not found.
*/
int lastIndexOf(E element, [int start]);
@@ -189,6 +197,7 @@
* Removes all elements in the list.
*
* The length of the list becomes zero.
+ *
* Throws an [UnsupportedError], and retains all elements, if the
* length of the list cannot be changed.
*/
@@ -220,7 +229,7 @@
* Overwrites elements of `this` with the elemenst of [iterable] starting
* at position [index] in the list.
*
- * This operation does not increase the length of the list.
+ * This operation does not increase the length of `this`.
*
* It is an error if the [index] does not point inside the list or at the
* position after the last element.
@@ -239,14 +248,18 @@
/**
* Removes the element at position [index] from the list.
*
- * This reduces the length of the list by one and moves all later elements
+ * This reduces the length of `this` by one and moves all later elements
* down by one position.
+ *
* Returns the removed element.
+ *
* Throws an [ArgumentError] if [index] is not an [int].
+ *
* Throws an [RangeError] if the [index] does not point inside
* the list.
+ *
* Throws an [UnsupportedError], and doesn't remove the element,
- * if the length of the list cannot be changed.
+ * if the length of `this` cannot be changed.
*/
E removeAt(int index);
@@ -274,9 +287,9 @@
/**
* Returns a new list containing the elements from [start] to [end].
*
- * If [end] is omitted, the [length] of the list is used.
+ * If [end] is omitted, the [length] of `this` is used.
*
- * It is an error if [start] or [end] are not list indices for this list,
+ * It is an error if [start] or [end] are not indices into `this`,
* or if [end] is before [start].
*/
List<E> sublist(int start, [int end]);
@@ -304,17 +317,24 @@
Iterable<E> getRange(int start, int end);
/**
- * Copies the elements of [iterable], skipping the [skipCount] first elements
+ * Copies the elements of [iterable], skipping the [skipCount] first elements,
* into the range [start] to [end] exclusive of `this`.
*
- * If [start] equals [end] and represent a legal range, this method has
- * no effect.
+ * If [start] equals [end] and [start]..[end] represents a legal range, this
+ * method has no effect.
*
* It is an error if [start]..[end] is not a valid range pointing into the
* `this`.
*
* It is an error if the [iterable] does not have enough elements after
* skipping [skipCount] elements.
+ *
+ * Example:
+ *
+ * var list = [1, 2, 3, 4];
+ * var list2 = [5, 6, 7, 8, 9];
+ * list.setRange(1, 3, list2, 3);
+ * print(list); // => [1, 8, 9, 4]
*/
void setRange(int start, int end, Iterable<E> iterable, [int skipCount = 0]);
diff --git a/sdk/lib/core/string.dart b/sdk/lib/core/string.dart
index ebcfe10..7db20f3 100644
--- a/sdk/lib/core/string.dart
+++ b/sdk/lib/core/string.dart
@@ -145,13 +145,31 @@
String substring(int startIndex, [int endIndex]);
/**
- * Removes leading and trailing whitespace from a string. If the string
- * contains leading or trailing whitespace a new string with no leading and
- * no trailing whitespace is returned. Otherwise, the string itself is
- * returned. Whitespace is defined as every Unicode character in the Zs, Zl
- * and Zp categories (this includes no-break space), the spacing control
- * characters from 9 to 13 (tab, lf, vtab, ff and cr), and 0xfeff the BOM
- * character.
+ * Removes leading and trailing whitespace from a string.
+ *
+ * If the string contains leading or trailing whitespace a new string with no
+ * leading and no trailing whitespace is returned. Otherwise, the string
+ * itself is returned.
+ *
+ * Whitespace is defined by the Unicode White_Space property (as defined in
+ * version 6.2 or later) and the BOM character, 0xFEFF.
+ *
+ * Here is the list of trimmed characters (following version 6.2):
+ *
+ * 0009..000D ; White_Space # Cc <control-0009>..<control-000D>
+ * 0020 ; White_Space # Zs SPACE
+ * 0085 ; White_Space # Cc <control-0085>
+ * 00A0 ; White_Space # Zs NO-BREAK SPACE
+ * 1680 ; White_Space # Zs OGHAM SPACE MARK
+ * 180E ; White_Space # Zs MONGOLIAN VOWEL SEPARATOR
+ * 2000..200A ; White_Space # Zs EN QUAD..HAIR SPACE
+ * 2028 ; White_Space # Zl LINE SEPARATOR
+ * 2029 ; White_Space # Zp PARAGRAPH SEPARATOR
+ * 202F ; White_Space # Zs NARROW NO-BREAK SPACE
+ * 205F ; White_Space # Zs MEDIUM MATHEMATICAL SPACE
+ * 3000 ; White_Space # Zs IDEOGRAPHIC SPACE
+ *
+ * FEFF ; BOM ZERO WIDTH NO_BREAK SPACE
*/
String trim();
diff --git a/sdk/lib/crypto/sha1.dart b/sdk/lib/crypto/sha1.dart
index 83e9217..8ee28ce 100644
--- a/sdk/lib/crypto/sha1.dart
+++ b/sdk/lib/crypto/sha1.dart
@@ -38,15 +38,15 @@
var n = _w[i - 3] ^ _w[i - 8] ^ _w[i - 14] ^ _w[i - 16];
_w[i] = _rotl32(n, 1);
}
- var t = _rotl32(a, 5) + e + _w[i];
+ var t = _add32(_add32(_rotl32(a, 5), e), _w[i]);
if (i < 20) {
- t = t + ((b & c) | (~b & d)) + 0x5A827999;
+ t = _add32(_add32(t, (b & c) | (~b & d)), 0x5A827999);
} else if (i < 40) {
- t = t + (b ^ c ^ d) + 0x6ED9EBA1;
+ t = _add32(_add32(t, (b ^ c ^ d)), 0x6ED9EBA1);
} else if (i < 60) {
- t = t + ((b & c) | (b & d) | (c & d)) + 0x8F1BBCDC;
+ t = _add32(_add32(t, (b & c) | (b & d) | (c & d)), 0x8F1BBCDC);
} else {
- t = t + (b ^ c ^ d) + 0xCA62C1D6;
+ t = _add32(_add32(t, b ^ c ^ d), 0xCA62C1D6);
}
e = d;
diff --git a/sdk/lib/html/dart2js/html_dart2js.dart b/sdk/lib/html/dart2js/html_dart2js.dart
index fc77a39..3bb3ec2 100644
--- a/sdk/lib/html/dart2js/html_dart2js.dart
+++ b/sdk/lib/html/dart2js/html_dart2js.dart
@@ -65,7 +65,7 @@
return JS('var', r'ReceivePortSync.dispatchCall(#, #)', id, message);
}
-spawnDomFunction(f) => IsolateNatives.spawnDomFunction(f);
+spawnDomFunction(Function f) => IsolateNatives.spawnDomFunction(f);
// 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.
@@ -1535,7 +1535,7 @@
'#.lineDashOffset || #.webkitLineDashOffset', this, this);
@DomName('CanvasRenderingContext2D.lineDashOffset')
- void set lineDashOffset(num value) => JS('void',
+ void set lineDashOffset(num value) => JS('void',
'typeof #.lineDashOffset != "undefined" ? #.lineDashOffset = # : '
'#.webkitLineDashOffset = #', this, this, value, this, value);
}
@@ -1662,7 +1662,7 @@
@DomName('Console')
class Console {
- static Console safeConsole = new Console();
+ static Console _safeConsole = new Console();
bool get _isConsoleDefined => JS('bool', 'typeof console != "undefined"');
@@ -1735,8 +1735,8 @@
JS('void', 'console.time(#)', title) : null;
@DomName('Console.timeEnd')
- void timeEnd(String timerName) => _isConsoleDefined ?
- JS('void', 'console.timeEnd(#)', timerName) : null;
+ void timeEnd(String title) => _isConsoleDefined ?
+ JS('void', 'console.timeEnd(#)', title) : null;
@DomName('Console.timeStamp')
void timeStamp(Object arg) => _isConsoleDefined ?
@@ -6110,6 +6110,10 @@
@DocsEditable
static const EventStreamProvider<Event> readyStateChangeEvent = const EventStreamProvider<Event>('readystatechange');
+ @DomName('Document.securitypolicyviolationEvent')
+ @DocsEditable
+ static const EventStreamProvider<SecurityPolicyViolationEvent> securityPolicyViolationEvent = const EventStreamProvider<SecurityPolicyViolationEvent>('securitypolicyviolation');
+
@DomName('Document.selectionchangeEvent')
@DocsEditable
static const EventStreamProvider<Event> selectionChangeEvent = const EventStreamProvider<Event>('selectionchange');
@@ -6634,6 +6638,10 @@
@DocsEditable
Stream<Event> get onSearch => Element.searchEvent.forTarget(this);
+ @DomName('Document.onsecuritypolicyviolation')
+ @DocsEditable
+ Stream<SecurityPolicyViolationEvent> get onSecurityPolicyViolation => securityPolicyViolationEvent.forTarget(this);
+
@DomName('Document.onselect')
@DocsEditable
Stream<Event> get onSelect => Element.selectEvent.forTarget(this);
@@ -7590,11 +7598,11 @@
* * [insertAdjacentText]
* * [insertAdjacentElement]
*/
- void insertAdjacentHtml(String where, String text) {
+ void insertAdjacentHtml(String where, String html) {
if (JS('bool', '!!#.insertAdjacentHtml', this)) {
- _insertAdjacentHtml(where, text);
+ _insertAdjacentHtml(where, html);
} else {
- _insertAdjacentNode(where, new DocumentFragment.html(text));
+ _insertAdjacentNode(where, new DocumentFragment.html(html));
}
}
@@ -7660,7 +7668,7 @@
throw new UnsupportedError("Not supported on this platform");
}
- @Creates('Null')
+ @Creates('Null') // Set from Dart code; does not instantiate a native type.
Map<String, StreamSubscription> _attributeBindings;
// TODO(jmesserly): I'm concerned about adding these to every element.
@@ -10039,7 +10047,19 @@
@DomName('FontLoader.loadEvent')
@DocsEditable
- static const EventStreamProvider<Event> loadEvent = const EventStreamProvider<Event>('load');
+ static const EventStreamProvider<CssFontFaceLoadEvent> loadEvent = const EventStreamProvider<CssFontFaceLoadEvent>('load');
+
+ @DomName('FontLoader.loadingEvent')
+ @DocsEditable
+ static const EventStreamProvider<CssFontFaceLoadEvent> loadingEvent = const EventStreamProvider<CssFontFaceLoadEvent>('loading');
+
+ @DomName('FontLoader.loadingdoneEvent')
+ @DocsEditable
+ static const EventStreamProvider<CssFontFaceLoadEvent> loadingDoneEvent = const EventStreamProvider<CssFontFaceLoadEvent>('loadingdone');
+
+ @DomName('FontLoader.loadstartEvent')
+ @DocsEditable
+ static const EventStreamProvider<CssFontFaceLoadEvent> loadStartEvent = const EventStreamProvider<CssFontFaceLoadEvent>('loadstart');
@DomName('FontLoader.loading')
@DocsEditable
@@ -10085,7 +10105,19 @@
@DomName('FontLoader.onload')
@DocsEditable
- Stream<Event> get onLoad => loadEvent.forTarget(this);
+ Stream<CssFontFaceLoadEvent> get onLoad => loadEvent.forTarget(this);
+
+ @DomName('FontLoader.onloading')
+ @DocsEditable
+ Stream<CssFontFaceLoadEvent> get onLoading => loadingEvent.forTarget(this);
+
+ @DomName('FontLoader.onloadingdone')
+ @DocsEditable
+ Stream<CssFontFaceLoadEvent> get onLoadingDone => loadingDoneEvent.forTarget(this);
+
+ @DomName('FontLoader.onloadstart')
+ @DocsEditable
+ Stream<CssFontFaceLoadEvent> get onLoadStart => loadStartEvent.forTarget(this);
}
// 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
@@ -10127,6 +10159,14 @@
@DomName('HTMLFormElement')
class FormElement extends Element native "HTMLFormElement" {
+ @DomName('HTMLFormElement.autocompleteEvent')
+ @DocsEditable
+ static const EventStreamProvider<Event> autocompleteEvent = const EventStreamProvider<Event>('autocomplete');
+
+ @DomName('HTMLFormElement.autocompleteerrorEvent')
+ @DocsEditable
+ static const EventStreamProvider<AutocompleteErrorEvent> autocompleteErrorEvent = const EventStreamProvider<AutocompleteErrorEvent>('autocompleteerror');
+
@DomName('HTMLFormElement.HTMLFormElement')
@DocsEditable
factory FormElement() => document.$dom_createElement("form");
@@ -10186,6 +10226,14 @@
@DomName('HTMLFormElement.submit')
@DocsEditable
void submit() native;
+
+ @DomName('HTMLFormElement.onautocomplete')
+ @DocsEditable
+ Stream<Event> get onAutocomplete => autocompleteEvent.forTarget(this);
+
+ @DomName('HTMLFormElement.onautocompleteerror')
+ @DocsEditable
+ Stream<AutocompleteErrorEvent> get onAutocompleteError => autocompleteErrorEvent.forTarget(this);
}
// 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
@@ -11372,39 +11420,6 @@
@DocsEditable
-@DomName('XMLHttpRequestException')
-class HttpRequestException native "XMLHttpRequestException" {
-
- @DomName('XMLHttpRequestException.ABORT_ERR')
- @DocsEditable
- static const int ABORT_ERR = 102;
-
- @DomName('XMLHttpRequestException.NETWORK_ERR')
- @DocsEditable
- static const int NETWORK_ERR = 101;
-
- @DomName('XMLHttpRequestException.code')
- @DocsEditable
- final int code;
-
- @DomName('XMLHttpRequestException.message')
- @DocsEditable
- final String message;
-
- @DomName('XMLHttpRequestException.name')
- @DocsEditable
- final String name;
-
- @DomName('XMLHttpRequestException.toString')
- @DocsEditable
- String toString() native;
-}
-// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-
-@DocsEditable
@DomName('XMLHttpRequestProgressEvent')
@SupportedBrowser(SupportedBrowser.CHROME)
@SupportedBrowser(SupportedBrowser.SAFARI)
@@ -14253,6 +14268,15 @@
@DocsEditable
+@DomName('MIDIInput')
+class MidiInput extends MidiPort implements EventTarget native "MIDIInput" {
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+
+@DocsEditable
@DomName('MIDIMessageEvent')
class MidiMessageEvent extends Event native "MIDIMessageEvent" {
@@ -14273,6 +14297,10 @@
@DomName('MIDIPort')
class MidiPort extends EventTarget native "MIDIPort" {
+ @DomName('MIDIPort.disconnectEvent')
+ @DocsEditable
+ static const EventStreamProvider<MidiConnectionEvent> disconnectEvent = const EventStreamProvider<MidiConnectionEvent>('disconnect');
+
@DomName('MIDIPort.id')
@DocsEditable
final String id;
@@ -14306,6 +14334,10 @@
@DomName('MIDIPort.removeEventListener')
@DocsEditable
void $dom_removeEventListener(String type, EventListener listener, [bool useCapture]) native;
+
+ @DomName('MIDIPort.ondisconnect')
+ @DocsEditable
+ Stream<MidiConnectionEvent> get onDisconnect => disconnectEvent.forTarget(this);
}
// 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
@@ -14568,13 +14600,12 @@
return new Point(x, y);
} else {
// Firefox does not support offsetX.
- var target = this.target;
- if (!(target is Element)) {
+ if (!(this.target is Element)) {
throw new UnsupportedError(
'offsetX is only supported on elements');
}
- return (this.client -
- this.target.getBoundingClientRect().topLeft).toInt();
+ Element target = this.target;
+ return (this.client - target.getBoundingClientRect().topLeft).toInt();
}
}
@@ -15127,11 +15158,12 @@
void addAll(Iterable<Node> iterable) {
if (iterable is _ChildNodeListLazy) {
- if (!identical(iterable._this, _this)) {
+ _ChildNodeListLazy otherList = iterable;
+ if (!identical(otherList._this, _this)) {
// Optimized route for copying between nodes.
- for (var i = 0, len = iterable.length; i < len; ++i) {
+ for (var i = 0, len = otherList.length; i < len; ++i) {
// Should use $dom_firstChild, Bug 8886.
- _this.append(iterable[0]);
+ _this.append(otherList[0]);
}
}
return;
@@ -16287,6 +16319,13 @@
@SupportedBrowser(SupportedBrowser.IE)
class Performance extends EventTarget native "Performance" {
+ @DomName('Performance.webkitresourcetimingbufferfullEvent')
+ @DocsEditable
+ @SupportedBrowser(SupportedBrowser.CHROME)
+ @SupportedBrowser(SupportedBrowser.SAFARI)
+ @Experimental
+ static const EventStreamProvider<Event> resourceTimingBufferFullEvent = const EventStreamProvider<Event>('webkitresourcetimingbufferfull');
+
/// Checks if this type is supported on the current platform.
static bool get supported => JS('bool', '!!(window.performance)');
@@ -16349,6 +16388,10 @@
@SupportedBrowser(SupportedBrowser.SAFARI)
@Experimental
void setResourceTimingBufferSize(int maxSize) native;
+
+ @DomName('Performance.onwebkitresourcetimingbufferfull')
+ @DocsEditable
+ Stream<Event> get onResourceTimingBufferFull => resourceTimingBufferFullEvent.forTarget(this);
}
// 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
@@ -17063,39 +17106,6 @@
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
-
-@DocsEditable
-@DomName('RangeException')
-class RangeException native "RangeException" {
-
- @DomName('RangeException.BAD_BOUNDARYPOINTS_ERR')
- @DocsEditable
- static const int BAD_BOUNDARYPOINTS_ERR = 1;
-
- @DomName('RangeException.INVALID_NODE_TYPE_ERR')
- @DocsEditable
- static const int INVALID_NODE_TYPE_ERR = 2;
-
- @DomName('RangeException.code')
- @DocsEditable
- final int code;
-
- @DomName('RangeException.message')
- @DocsEditable
- final String message;
-
- @DomName('RangeException.name')
- @DocsEditable
- final String name;
-
- @DomName('RangeException.toString')
- @DocsEditable
- String toString() native;
-}
-// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
// WARNING: Do not edit - generated code.
@@ -18881,14 +18891,34 @@
@DomName('SpeechSynthesisUtterance')
class SpeechSynthesisUtterance extends EventTarget native "SpeechSynthesisUtterance" {
+ @DomName('SpeechSynthesisUtterance.boundaryEvent')
+ @DocsEditable
+ static const EventStreamProvider<SpeechSynthesisEvent> boundaryEvent = const EventStreamProvider<SpeechSynthesisEvent>('boundary');
+
+ @DomName('SpeechSynthesisUtterance.endEvent')
+ @DocsEditable
+ static const EventStreamProvider<SpeechSynthesisEvent> endEvent = const EventStreamProvider<SpeechSynthesisEvent>('end');
+
@DomName('SpeechSynthesisUtterance.errorEvent')
@DocsEditable
static const EventStreamProvider<Event> errorEvent = const EventStreamProvider<Event>('error');
+ @DomName('SpeechSynthesisUtterance.markEvent')
+ @DocsEditable
+ static const EventStreamProvider<SpeechSynthesisEvent> markEvent = const EventStreamProvider<SpeechSynthesisEvent>('mark');
+
@DomName('SpeechSynthesisUtterance.pauseEvent')
@DocsEditable
static const EventStreamProvider<Event> pauseEvent = const EventStreamProvider<Event>('pause');
+ @DomName('SpeechSynthesisUtterance.resumeEvent')
+ @DocsEditable
+ static const EventStreamProvider<SpeechSynthesisEvent> resumeEvent = const EventStreamProvider<SpeechSynthesisEvent>('resume');
+
+ @DomName('SpeechSynthesisUtterance.startEvent')
+ @DocsEditable
+ static const EventStreamProvider<SpeechSynthesisEvent> startEvent = const EventStreamProvider<SpeechSynthesisEvent>('start');
+
@DomName('SpeechSynthesisUtterance.SpeechSynthesisUtterance')
@DocsEditable
factory SpeechSynthesisUtterance([String text]) {
@@ -18924,13 +18954,33 @@
@DocsEditable
num volume;
+ @DomName('SpeechSynthesisUtterance.onboundary')
+ @DocsEditable
+ Stream<SpeechSynthesisEvent> get onBoundary => boundaryEvent.forTarget(this);
+
+ @DomName('SpeechSynthesisUtterance.onend')
+ @DocsEditable
+ Stream<SpeechSynthesisEvent> get onEnd => endEvent.forTarget(this);
+
@DomName('SpeechSynthesisUtterance.onerror')
@DocsEditable
Stream<Event> get onError => errorEvent.forTarget(this);
+ @DomName('SpeechSynthesisUtterance.onmark')
+ @DocsEditable
+ Stream<SpeechSynthesisEvent> get onMark => markEvent.forTarget(this);
+
@DomName('SpeechSynthesisUtterance.onpause')
@DocsEditable
Stream<Event> get onPause => pauseEvent.forTarget(this);
+
+ @DomName('SpeechSynthesisUtterance.onresume')
+ @DocsEditable
+ Stream<SpeechSynthesisEvent> get onResume => resumeEvent.forTarget(this);
+
+ @DomName('SpeechSynthesisUtterance.onstart')
+ @DocsEditable
+ Stream<SpeechSynthesisEvent> get onStart => startEvent.forTarget(this);
}
// 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
@@ -20822,9 +20872,9 @@
'(self.URL || self.webkitURL).createObjectURL(#)',
blob_OR_source_OR_stream);
- static void revokeObjectUrl(String objectUrl) =>
+ static void revokeObjectUrl(String url) =>
JS('void',
- '(self.URL || self.webkitURL).revokeObjectURL(#)', objectUrl);
+ '(self.URL || self.webkitURL).revokeObjectURL(#)', url);
}
// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
@@ -21535,7 +21585,7 @@
return _requestAnimationFrame(callback);
}
- void cancelAnimationFrame(id) {
+ void cancelAnimationFrame(int id) {
_ensureRequestAnimationFrame();
_cancelAnimationFrame(id);
}
@@ -21588,7 +21638,7 @@
this, this, this);
@DomName('Window.console')
- Console get console => Console.safeConsole;
+ Console get console => Console._safeConsole;
/// Checks if _setImmediate is supported.
static bool get _supportsSetImmediate =>
@@ -24450,16 +24500,16 @@
}
}
- bool get _paused => _pauseCount > 0;
+ bool get isPaused => _pauseCount > 0;
void resume() {
- if (_canceled || !_paused) return;
+ if (_canceled || !isPaused) return;
--_pauseCount;
_tryResume();
}
void _tryResume() {
- if (_onData != null && !_paused) {
+ if (_onData != null && !isPaused) {
_target.$dom_addEventListener(_eventType, _onData, _useCapture);
}
}
@@ -24583,7 +24633,7 @@
throw new UnsupportedError("Cannot remove from immutable List.");
}
- void remove(Object object) {
+ bool remove(Object object) {
throw new UnsupportedError("Cannot remove from immutable List.");
}
@@ -24595,7 +24645,7 @@
throw new UnsupportedError("Cannot remove from immutable List.");
}
- void setRange(int start, int end, Iterable<E> iterable, [int skipCount]) {
+ void setRange(int start, int end, Iterable<E> iterable, [int skipCount = 0]) {
throw new UnsupportedError("Cannot setRange on immutable List.");
}
@@ -26667,7 +26717,7 @@
}
// http://dvcs.w3.org/hg/webcomponents/raw-file/tip/spec/templates/index.html#dfn-template-contents-owner
- static Document _getTemplateContentsOwner(Document doc) {
+ static Document _getTemplateContentsOwner(HtmlDocument doc) {
if (doc.window == null) {
return doc;
}
@@ -26745,7 +26795,7 @@
// template.
// TODO(jmesserly): node is DocumentFragment or Element
var descendents = (node as dynamic).queryAll(_allTemplatesSelectors);
- if (node is Element && node.isTemplate) bootstrap(node);
+ if (node is Element && (node as Element).isTemplate) bootstrap(node);
descendents.forEach(bootstrap);
}
@@ -26899,7 +26949,7 @@
static void _removeChild(Node parent, Node child) {
child._templateInstance = null;
- if (child is Element && child.isTemplate) {
+ if (child is Element && (child as Element).isTemplate) {
// Make sure we stop observing when we remove an element.
var templateIterator = child._templateIterator;
if (templateIterator != null) {
@@ -27734,7 +27784,7 @@
void add(E element) { _list.add(element); }
- void remove(Object element) { _list.remove(element); }
+ bool remove(Object element) => _list.remove(element);
void clear() { _list.clear(); }
@@ -27869,8 +27919,14 @@
// Assume it's a Window if it contains the setInterval property. It may be
// from a different frame - without a patched prototype - so we cannot
// rely on Dart type checking.
- if (JS('bool', r'"setInterval" in #', e))
- return _DOMWindowCrossFrame._createSafe(e);
+ if (JS('bool', r'"setInterval" in #', e)) {
+ var window = _DOMWindowCrossFrame._createSafe(e);
+ // If it's a native window.
+ if (window is EventTarget) {
+ return window;
+ }
+ return null;
+ }
else
return e;
}
diff --git a/sdk/lib/html/dartium/html_dartium.dart b/sdk/lib/html/dartium/html_dartium.dart
index 6c139d5..0a9d8af 100644
--- a/sdk/lib/html/dartium/html_dartium.dart
+++ b/sdk/lib/html/dartium/html_dartium.dart
@@ -1435,7 +1435,7 @@
@DocsEditable
CanvasGradient createRadialGradient(num x0, num y0, num r0, num x1, num y1, num r1) native "CanvasRenderingContext2D_createRadialGradient_Callback";
- void $dom_drawImage(canvas_OR_image_OR_video, num sx_OR_x, num sy_OR_y, [num sw_OR_width, num height_OR_sh, num dx, num dy, num dw, num dh]) {
+ void _drawImage(canvas_OR_image_OR_video, num sx_OR_x, num sy_OR_y, [num sw_OR_width, num height_OR_sh, num dx, num dy, num dw, num dh]) {
if ((canvas_OR_image_OR_video is ImageElement || canvas_OR_image_OR_video == null) && (sx_OR_x is num || sx_OR_x == null) && (sy_OR_y is num || sy_OR_y == null) && !?sw_OR_width && !?height_OR_sh && !?dx && !?dy && !?dw && !?dh) {
_drawImage_1(canvas_OR_image_OR_video, sx_OR_x, sy_OR_y);
return;
@@ -1758,13 +1758,13 @@
void drawImageToRect(CanvasImageSource source, Rect destRect,
{Rect sourceRect}) {
if (sourceRect == null) {
- $dom_drawImage(source,
+ _drawImage(source,
destRect.left,
destRect.top,
destRect.width,
destRect.height);
} else {
- $dom_drawImage(source,
+ _drawImage(source,
sourceRect.left,
sourceRect.top,
sourceRect.width,
@@ -1807,7 +1807,7 @@
*/
@DomName('CanvasRenderingContext2D.drawImage')
void drawImage(CanvasImageSource source, num destX, num destY) {
- $dom_drawImage(source, destX, destY);
+ _drawImage(source, destX, destY);
}
/**
@@ -1839,7 +1839,7 @@
@DomName('CanvasRenderingContext2D.drawImage')
void drawImageScaled(CanvasImageSource source,
num destX, num destY, num destWidth, num destHeight) {
- $dom_drawImage(source, destX, destY, destWidth, destHeight);
+ _drawImage(source, destX, destY, destWidth, destHeight);
}
/**
@@ -1875,7 +1875,7 @@
void drawImageScaledFromSource(CanvasImageSource source,
num sourceX, num sourceY, num sourceWidth, num sourceHeight,
num destX, num destY, num destWidth, num destHeight) {
- $dom_drawImage(source, sourceX, sourceY, sourceWidth, sourceHeight,
+ _drawImage(source, sourceX, sourceY, sourceWidth, sourceHeight,
destX, destY, destWidth, destHeight);
}
@@ -6572,6 +6572,10 @@
@DocsEditable
static const EventStreamProvider<Event> readyStateChangeEvent = const EventStreamProvider<Event>('readystatechange');
+ @DomName('Document.securitypolicyviolationEvent')
+ @DocsEditable
+ static const EventStreamProvider<SecurityPolicyViolationEvent> securityPolicyViolationEvent = const EventStreamProvider<SecurityPolicyViolationEvent>('securitypolicyviolation');
+
@DomName('Document.selectionchangeEvent')
@DocsEditable
static const EventStreamProvider<Event> selectionChangeEvent = const EventStreamProvider<Event>('selectionchange');
@@ -7062,6 +7066,10 @@
@DocsEditable
Stream<Event> get onSearch => Element.searchEvent.forTarget(this);
+ @DomName('Document.onsecuritypolicyviolation')
+ @DocsEditable
+ Stream<SecurityPolicyViolationEvent> get onSecurityPolicyViolation => securityPolicyViolationEvent.forTarget(this);
+
@DomName('Document.onselect')
@DocsEditable
Stream<Event> get onSelect => Element.selectEvent.forTarget(this);
@@ -7975,7 +7983,6 @@
}
- @Creates('Null')
Map<String, StreamSubscription> _attributeBindings;
// TODO(jmesserly): I'm concerned about adding these to every element.
@@ -10425,7 +10432,19 @@
@DomName('FontLoader.loadEvent')
@DocsEditable
- static const EventStreamProvider<Event> loadEvent = const EventStreamProvider<Event>('load');
+ static const EventStreamProvider<CssFontFaceLoadEvent> loadEvent = const EventStreamProvider<CssFontFaceLoadEvent>('load');
+
+ @DomName('FontLoader.loadingEvent')
+ @DocsEditable
+ static const EventStreamProvider<CssFontFaceLoadEvent> loadingEvent = const EventStreamProvider<CssFontFaceLoadEvent>('loading');
+
+ @DomName('FontLoader.loadingdoneEvent')
+ @DocsEditable
+ static const EventStreamProvider<CssFontFaceLoadEvent> loadingDoneEvent = const EventStreamProvider<CssFontFaceLoadEvent>('loadingdone');
+
+ @DomName('FontLoader.loadstartEvent')
+ @DocsEditable
+ static const EventStreamProvider<CssFontFaceLoadEvent> loadStartEvent = const EventStreamProvider<CssFontFaceLoadEvent>('loadstart');
@DomName('FontLoader.loading')
@DocsEditable
@@ -10461,7 +10480,19 @@
@DomName('FontLoader.onload')
@DocsEditable
- Stream<Event> get onLoad => loadEvent.forTarget(this);
+ Stream<CssFontFaceLoadEvent> get onLoad => loadEvent.forTarget(this);
+
+ @DomName('FontLoader.onloading')
+ @DocsEditable
+ Stream<CssFontFaceLoadEvent> get onLoading => loadingEvent.forTarget(this);
+
+ @DomName('FontLoader.onloadingdone')
+ @DocsEditable
+ Stream<CssFontFaceLoadEvent> get onLoadingDone => loadingDoneEvent.forTarget(this);
+
+ @DomName('FontLoader.onloadstart')
+ @DocsEditable
+ Stream<CssFontFaceLoadEvent> get onLoadStart => loadStartEvent.forTarget(this);
}
// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
@@ -10504,6 +10535,14 @@
class FormElement extends _Element_Merged {
FormElement.internal() : super.internal();
+ @DomName('HTMLFormElement.autocompleteEvent')
+ @DocsEditable
+ static const EventStreamProvider<Event> autocompleteEvent = const EventStreamProvider<Event>('autocomplete');
+
+ @DomName('HTMLFormElement.autocompleteerrorEvent')
+ @DocsEditable
+ static const EventStreamProvider<AutocompleteErrorEvent> autocompleteErrorEvent = const EventStreamProvider<AutocompleteErrorEvent>('autocompleteerror');
+
@DomName('HTMLFormElement.HTMLFormElement')
@DocsEditable
factory FormElement() => document.$dom_createElement("form");
@@ -10600,6 +10639,14 @@
@DocsEditable
void submit() native "HTMLFormElement_submit_Callback";
+ @DomName('HTMLFormElement.onautocomplete')
+ @DocsEditable
+ Stream<Event> get onAutocomplete => autocompleteEvent.forTarget(this);
+
+ @DomName('HTMLFormElement.onautocompleteerror')
+ @DocsEditable
+ Stream<AutocompleteErrorEvent> get onAutocompleteError => autocompleteErrorEvent.forTarget(this);
+
}
// 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
@@ -11815,43 +11862,6 @@
@DocsEditable
-@DomName('XMLHttpRequestException')
-class HttpRequestException extends NativeFieldWrapperClass1 {
- HttpRequestException.internal();
-
- @DomName('XMLHttpRequestException.ABORT_ERR')
- @DocsEditable
- static const int ABORT_ERR = 102;
-
- @DomName('XMLHttpRequestException.NETWORK_ERR')
- @DocsEditable
- static const int NETWORK_ERR = 101;
-
- @DomName('XMLHttpRequestException.code')
- @DocsEditable
- int get code native "XMLHttpRequestException_code_Getter";
-
- @DomName('XMLHttpRequestException.message')
- @DocsEditable
- String get message native "XMLHttpRequestException_message_Getter";
-
- @DomName('XMLHttpRequestException.name')
- @DocsEditable
- String get name native "XMLHttpRequestException_name_Getter";
-
- @DomName('XMLHttpRequestException.toString')
- @DocsEditable
- String toString() native "XMLHttpRequestException_toString_Callback";
-
-}
-// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-// WARNING: Do not edit - generated code.
-
-
-@DocsEditable
@DomName('XMLHttpRequestProgressEvent')
@SupportedBrowser(SupportedBrowser.CHROME)
@SupportedBrowser(SupportedBrowser.SAFARI)
@@ -15267,6 +15277,19 @@
@DocsEditable
+@DomName('MIDIInput')
+class MidiInput extends MidiPort implements EventTarget {
+ MidiInput.internal() : super.internal();
+
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// WARNING: Do not edit - generated code.
+
+
+@DocsEditable
@DomName('MIDIMessageEvent')
class MidiMessageEvent extends Event {
MidiMessageEvent.internal() : super.internal();
@@ -15292,6 +15315,10 @@
class MidiPort extends EventTarget {
MidiPort.internal() : super.internal();
+ @DomName('MIDIPort.disconnectEvent')
+ @DocsEditable
+ static const EventStreamProvider<MidiConnectionEvent> disconnectEvent = const EventStreamProvider<MidiConnectionEvent>('disconnect');
+
@DomName('MIDIPort.id')
@DocsEditable
String get id native "MIDIPort_id_Getter";
@@ -15324,6 +15351,10 @@
@DocsEditable
void $dom_removeEventListener(String type, EventListener listener, [bool useCapture]) native "MIDIPort_removeEventListener_Callback";
+ @DomName('MIDIPort.ondisconnect')
+ @DocsEditable
+ Stream<MidiConnectionEvent> get onDisconnect => disconnectEvent.forTarget(this);
+
}
// 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
@@ -16123,11 +16154,12 @@
void addAll(Iterable<Node> iterable) {
if (iterable is _ChildNodeListLazy) {
- if (!identical(iterable._this, _this)) {
+ _ChildNodeListLazy otherList = iterable;
+ if (!identical(otherList._this, _this)) {
// Optimized route for copying between nodes.
- for (var i = 0, len = iterable.length; i < len; ++i) {
+ for (var i = 0, len = otherList.length; i < len; ++i) {
// Should use $dom_firstChild, Bug 8886.
- _this.append(iterable[0]);
+ _this.append(otherList[0]);
}
}
return;
@@ -17409,6 +17441,13 @@
class Performance extends EventTarget {
Performance.internal() : super.internal();
+ @DomName('Performance.webkitresourcetimingbufferfullEvent')
+ @DocsEditable
+ @SupportedBrowser(SupportedBrowser.CHROME)
+ @SupportedBrowser(SupportedBrowser.SAFARI)
+ @Experimental
+ static const EventStreamProvider<Event> resourceTimingBufferFullEvent = const EventStreamProvider<Event>('webkitresourcetimingbufferfull');
+
/// Checks if this type is supported on the current platform.
static bool get supported => true;
@@ -17470,6 +17509,10 @@
@Experimental
void setResourceTimingBufferSize(int maxSize) native "Performance_webkitSetResourceTimingBufferSize_Callback";
+ @DomName('Performance.onwebkitresourcetimingbufferfull')
+ @DocsEditable
+ Stream<Event> get onResourceTimingBufferFull => resourceTimingBufferFullEvent.forTarget(this);
+
}
// 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
@@ -18260,43 +18303,6 @@
// WARNING: Do not edit - generated code.
-@DocsEditable
-@DomName('RangeException')
-class RangeException extends NativeFieldWrapperClass1 {
- RangeException.internal();
-
- @DomName('RangeException.BAD_BOUNDARYPOINTS_ERR')
- @DocsEditable
- static const int BAD_BOUNDARYPOINTS_ERR = 1;
-
- @DomName('RangeException.INVALID_NODE_TYPE_ERR')
- @DocsEditable
- static const int INVALID_NODE_TYPE_ERR = 2;
-
- @DomName('RangeException.code')
- @DocsEditable
- int get code native "RangeException_code_Getter";
-
- @DomName('RangeException.message')
- @DocsEditable
- String get message native "RangeException_message_Getter";
-
- @DomName('RangeException.name')
- @DocsEditable
- String get name native "RangeException_name_Getter";
-
- @DomName('RangeException.toString')
- @DocsEditable
- String toString() native "RangeException_toString_Callback";
-
-}
-// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-// WARNING: Do not edit - generated code.
-
-
typedef void RequestAnimationFrameCallback(num highResTime);
// 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
@@ -20286,14 +20292,34 @@
class SpeechSynthesisUtterance extends EventTarget {
SpeechSynthesisUtterance.internal() : super.internal();
+ @DomName('SpeechSynthesisUtterance.boundaryEvent')
+ @DocsEditable
+ static const EventStreamProvider<SpeechSynthesisEvent> boundaryEvent = const EventStreamProvider<SpeechSynthesisEvent>('boundary');
+
+ @DomName('SpeechSynthesisUtterance.endEvent')
+ @DocsEditable
+ static const EventStreamProvider<SpeechSynthesisEvent> endEvent = const EventStreamProvider<SpeechSynthesisEvent>('end');
+
@DomName('SpeechSynthesisUtterance.errorEvent')
@DocsEditable
static const EventStreamProvider<Event> errorEvent = const EventStreamProvider<Event>('error');
+ @DomName('SpeechSynthesisUtterance.markEvent')
+ @DocsEditable
+ static const EventStreamProvider<SpeechSynthesisEvent> markEvent = const EventStreamProvider<SpeechSynthesisEvent>('mark');
+
@DomName('SpeechSynthesisUtterance.pauseEvent')
@DocsEditable
static const EventStreamProvider<Event> pauseEvent = const EventStreamProvider<Event>('pause');
+ @DomName('SpeechSynthesisUtterance.resumeEvent')
+ @DocsEditable
+ static const EventStreamProvider<SpeechSynthesisEvent> resumeEvent = const EventStreamProvider<SpeechSynthesisEvent>('resume');
+
+ @DomName('SpeechSynthesisUtterance.startEvent')
+ @DocsEditable
+ static const EventStreamProvider<SpeechSynthesisEvent> startEvent = const EventStreamProvider<SpeechSynthesisEvent>('start');
+
@DomName('SpeechSynthesisUtterance.SpeechSynthesisUtterance')
@DocsEditable
factory SpeechSynthesisUtterance([String text]) {
@@ -20351,14 +20377,34 @@
@DocsEditable
void set volume(num value) native "SpeechSynthesisUtterance_volume_Setter";
+ @DomName('SpeechSynthesisUtterance.onboundary')
+ @DocsEditable
+ Stream<SpeechSynthesisEvent> get onBoundary => boundaryEvent.forTarget(this);
+
+ @DomName('SpeechSynthesisUtterance.onend')
+ @DocsEditable
+ Stream<SpeechSynthesisEvent> get onEnd => endEvent.forTarget(this);
+
@DomName('SpeechSynthesisUtterance.onerror')
@DocsEditable
Stream<Event> get onError => errorEvent.forTarget(this);
+ @DomName('SpeechSynthesisUtterance.onmark')
+ @DocsEditable
+ Stream<SpeechSynthesisEvent> get onMark => markEvent.forTarget(this);
+
@DomName('SpeechSynthesisUtterance.onpause')
@DocsEditable
Stream<Event> get onPause => pauseEvent.forTarget(this);
+ @DomName('SpeechSynthesisUtterance.onresume')
+ @DocsEditable
+ Stream<SpeechSynthesisEvent> get onResume => resumeEvent.forTarget(this);
+
+ @DomName('SpeechSynthesisUtterance.onstart')
+ @DocsEditable
+ Stream<SpeechSynthesisEvent> get onStart => startEvent.forTarget(this);
+
}
// 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
@@ -22936,11 +22982,11 @@
@DomName('WheelEvent.wheelDeltaX')
@DocsEditable
- int get $dom_wheelDeltaX native "WheelEvent_wheelDeltaX_Getter";
+ int get _wheelDeltaX native "WheelEvent_wheelDeltaX_Getter";
@DomName('WheelEvent.wheelDeltaY')
@DocsEditable
- int get $dom_wheelDeltaY native "WheelEvent_wheelDeltaY_Getter";
+ int get _wheelDeltaY native "WheelEvent_wheelDeltaY_Getter";
@DomName('WheelEvent.initWebKitWheelEvent')
@DocsEditable
@@ -22956,7 +23002,7 @@
* * [WheelEvent.deltaX](http://dev.w3.org/2006/webapi/DOM-Level-3-Events/html/DOM3-Events.html#events-WheelEvent-deltaX) from the W3C.
*/
@DomName('WheelEvent.deltaX')
- num get deltaX => -$dom_wheelDeltaX;
+ num get deltaX => -_wheelDeltaX;
/**
* The amount that is expected to scroll vertically, in units determined by
@@ -22967,7 +23013,7 @@
* * [WheelEvent.deltaY](http://dev.w3.org/2006/webapi/DOM-Level-3-Events/html/DOM3-Events.html#events-WheelEvent-deltaY) from the W3C.
*/
@DomName('WheelEvent.deltaY')
- num get deltaY => -$dom_wheelDeltaY;
+ num get deltaY => -_wheelDeltaY;
}
// 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
@@ -26243,16 +26289,16 @@
}
}
- bool get _paused => _pauseCount > 0;
+ bool get isPaused => _pauseCount > 0;
void resume() {
- if (_canceled || !_paused) return;
+ if (_canceled || !isPaused) return;
--_pauseCount;
_tryResume();
}
void _tryResume() {
- if (_onData != null && !_paused) {
+ if (_onData != null && !isPaused) {
_target.$dom_addEventListener(_eventType, _onData, _useCapture);
}
}
@@ -26376,7 +26422,7 @@
throw new UnsupportedError("Cannot remove from immutable List.");
}
- void remove(Object object) {
+ bool remove(Object object) {
throw new UnsupportedError("Cannot remove from immutable List.");
}
@@ -26388,7 +26434,7 @@
throw new UnsupportedError("Cannot remove from immutable List.");
}
- void setRange(int start, int end, Iterable<E> iterable, [int skipCount]) {
+ void setRange(int start, int end, Iterable<E> iterable, [int skipCount = 0]) {
throw new UnsupportedError("Cannot setRange on immutable List.");
}
@@ -28460,7 +28506,7 @@
}
// http://dvcs.w3.org/hg/webcomponents/raw-file/tip/spec/templates/index.html#dfn-template-contents-owner
- static Document _getTemplateContentsOwner(Document doc) {
+ static Document _getTemplateContentsOwner(HtmlDocument doc) {
if (doc.window == null) {
return doc;
}
@@ -28538,7 +28584,7 @@
// template.
// TODO(jmesserly): node is DocumentFragment or Element
var descendents = (node as dynamic).queryAll(_allTemplatesSelectors);
- if (node is Element && node.isTemplate) bootstrap(node);
+ if (node is Element && (node as Element).isTemplate) bootstrap(node);
descendents.forEach(bootstrap);
}
@@ -28692,7 +28738,7 @@
static void _removeChild(Node parent, Node child) {
child._templateInstance = null;
- if (child is Element && child.isTemplate) {
+ if (child is Element && (child as Element).isTemplate) {
// Make sure we stop observing when we remove an element.
var templateIterator = child._templateIterator;
if (templateIterator != null) {
@@ -28945,7 +28991,7 @@
void add(E element) { _list.add(element); }
- void remove(Object element) { _list.remove(element); }
+ bool remove(Object element) => _list.remove(element);
void clear() { _list.clear(); }
@@ -29141,6 +29187,8 @@
/** True if the altGraphKey is pressed during this event. */
bool get altGraphKey => _parent.altGraphKey;
+ /** Accessor to the clipboardData available for this event. */
+ DataTransfer get clipboardData => _parent.clipboardData;
/** True if the ctrl key is pressed during this event. */
bool get ctrlKey => _parent.ctrlKey;
int get detail => _parent.detail;
diff --git a/sdk/lib/io/base64.dart b/sdk/lib/io/base64.dart
deleted file mode 100644
index 1469c8d..0000000
--- a/sdk/lib/io/base64.dart
+++ /dev/null
@@ -1,106 +0,0 @@
-// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-part of dart.io;
-
-class _Base64 {
- static const List<String> _encodingTable = const [
- 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O',
- 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd',
- 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's',
- 't', 'u', 'v', 'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7',
- '8', '9', '+', '/'];
-
- /**
- * Base64 transfer encoding for MIME (RFC 2045)
- */
- static String _encode(List<int> data) {
- List<String> characters = new List<String>();
- int i;
- for (i = 0; i + 3 <= data.length; i += 3) {
- int value = 0;
- value |= data[i + 2];
- value |= data[i + 1] << 8;
- value |= data[i] << 16;
- for (int j = 0; j < 4; j++) {
- int index = (value >> ((3 - j) * 6)) & ((1 << 6) - 1);
- characters.add(_encodingTable[index]);
- }
- }
- // Remainders.
- if (i + 2 == data.length) {
- int value = 0;
- value |= data[i + 1] << 8;
- value |= data[i] << 16;
- for (int j = 0; j < 3; j++) {
- int index = (value >> ((3 - j) * 6)) & ((1 << 6) - 1);
- characters.add(_encodingTable[index]);
- }
- characters.add("=");
- } else if (i + 1 == data.length) {
- int value = 0;
- value |= data[i] << 16;
- for (int j = 0; j < 2; j++) {
- int index = (value >> ((3 - j) * 6)) & ((1 << 6) - 1);
- characters.add(_encodingTable[index]);
- }
- characters.add("=");
- characters.add("=");
- }
- StringBuffer output = new StringBuffer();
- for (i = 0; i < characters.length; i++) {
- if (i > 0 && i % 76 == 0) {
- output.write("\r\n");
- }
- output.write(characters[i]);
- }
- return output.toString();
- }
-
-
- /**
- * Base64 transfer decoding for MIME (RFC 2045).
- */
- static List<int> _decode(String data) {
- List<int> result = new List<int>();
- int padCount = 0;
- int charCount = 0;
- int value = 0;
- for (int i = 0; i < data.length; i++) {
- int char = data.codeUnitAt(i);
- if (65 <= char && char <= 90) { // "A" - "Z".
- value = (value << 6) | char - 65;
- charCount++;
- } else if (97 <= char && char <= 122) { // "a" - "z".
- value = (value << 6) | char - 97 + 26;
- charCount++;
- } else if (48 <= char && char <= 57) { // "0" - "9".
- value = (value << 6) | char - 48 + 52;
- charCount++;
- } else if (char == 43) { // "+".
- value = (value << 6) | 62;
- charCount++;
- } else if (char == 47) { // "/".
- value = (value << 6) | 63;
- charCount++;
- } else if (char == 61) { // "=".
- value = (value << 6);
- charCount++;
- padCount++;
- }
- if (charCount == 4) {
- result.add((value & 0xFF0000) >> 16);
- if (padCount < 2) {
- result.add((value & 0xFF00) >> 8);
- }
- if (padCount == 0) {
- result.add(value & 0xFF);
- }
- charCount = 0;
- value = 0;
- }
- }
- return result;
- }
-}
diff --git a/sdk/lib/io/file.dart b/sdk/lib/io/file.dart
index 20110af..eb3dcd7 100644
--- a/sdk/lib/io/file.dart
+++ b/sdk/lib/io/file.dart
@@ -180,14 +180,19 @@
String fullPathSync();
/**
- * Create a new independent [Stream](../dart_async/Stream.html) for the
- * contents of this file.
+ * Create a new independent [Stream] for the contents of this file.
+ *
+ * If [start] is present, the file will be read from byte-offset [start].
+ * Otherwise from the beginning (index 0).
+ *
+ * If [end] is present, only up to byte-index [end] will be read. Otherwise,
+ * until end of file.
*
* In order to make sure that system resources are freed, the stream
* must be read to completion or the subscription on the stream must
* be cancelled.
*/
- Stream<List<int>> openRead();
+ Stream<List<int>> openRead([int start, int end]);
/**
* Creates a new independent [IOSink] for the file. The
diff --git a/sdk/lib/io/file_impl.dart b/sdk/lib/io/file_impl.dart
index 15fbded..fb6b272 100644
--- a/sdk/lib/io/file_impl.dart
+++ b/sdk/lib/io/file_impl.dart
@@ -16,6 +16,7 @@
String _path;
RandomAccessFile _openedFile;
int _position;
+ int _end;
// Has the stream been paused or unsubscribed?
bool _paused = false;
@@ -27,7 +28,7 @@
// Block read but not yet send because stream is paused.
List<int> _currentBlock;
- _FileStream(String this._path) : _position = 0 {
+ _FileStream(String this._path, this._position, this._end) {
_setupController();
}
@@ -71,7 +72,19 @@
// Don't start a new read if one is already in progress.
if (_readInProgress) return;
_readInProgress = true;
- _openedFile.read(_BLOCK_SIZE)
+ int readBytes = _BLOCK_SIZE;
+ if (_end != null) {
+ readBytes = min(readBytes, _end - _position);
+ if (readBytes < 0) {
+ if (!_unsubscribed) {
+ _controller.addError(new RangeError("Bad end position: $_end"));
+ _closeFile().then((_) { _controller.close(); });
+ _unsubscribed = true;
+ }
+ return;
+ }
+ }
+ _openedFile.read(readBytes)
.then((block) {
_readInProgress = false;
if (block.length == 0) {
@@ -99,6 +112,13 @@
}
void _start() {
+ if (_position == null) {
+ _position = 0;
+ } else if (_position < 0) {
+ _controller.addError(new RangeError("Bad start position: $_position"));
+ _controller.close();
+ return;
+ }
Future<RandomAccessFile> openFuture;
if (_path != null) {
openFuture = new File(_path).open(mode: FileMode.READ);
@@ -108,8 +128,11 @@
openFuture
.then((RandomAccessFile opened) {
_openedFile = opened;
- _readBlock();
+ if (_position > 0) {
+ return opened.setPosition(_position);
+ }
})
+ .then((_) => _readBlock())
.catchError((e) {
_controller.addError(e);
_controller.close();
@@ -315,14 +338,10 @@
Future<RandomAccessFile> open({FileMode mode: FileMode.READ}) {
_ensureFileService();
- Completer<RandomAccessFile> completer = new Completer<RandomAccessFile>();
if (mode != FileMode.READ &&
mode != FileMode.WRITE &&
mode != FileMode.APPEND) {
- Timer.run(() {
- completer.completeError(new ArgumentError());
- });
- return completer.future;
+ return new Future.error(new ArgumentError());
}
List request = new List(3);
request[0] = _OPEN_REQUEST;
@@ -430,8 +449,8 @@
return result;
}
- Stream<List<int>> openRead() {
- return new _FileStream(_path);
+ Stream<List<int>> openRead([int start, int end]) {
+ return new _FileStream(_path, start, end);
}
IOSink openWrite({FileMode mode: FileMode.WRITE,
@@ -500,7 +519,6 @@
Future<List<String>> readAsLines({Encoding encoding: Encoding.UTF_8}) {
_ensureFileService();
- Completer<List<String>> completer = new Completer<List<String>>();
return readAsBytes().then((bytes) {
return _decodeLines(bytes, encoding);
});
@@ -534,9 +552,7 @@
try {
return writeAsBytes(_encodeString(contents, encoding), mode: mode);
} catch (e) {
- var completer = new Completer();
- Timer.run(() => completer.completeError(e));
- return completer.future;
+ return new Future.error(e);
}
}
@@ -572,8 +588,7 @@
_RandomAccessFile(int this._id, String this._path);
Future<RandomAccessFile> close() {
- Completer<RandomAccessFile> completer = new Completer<RandomAccessFile>();
- if (closed) return _completeWithClosedException(completer);
+ if (closed) return _closedException();
_ensureFileService();
List request = new List(2);
request[0] = _CLOSE_REQUEST;
@@ -604,8 +619,7 @@
Future<int> readByte() {
_ensureFileService();
- Completer<int> completer = new Completer<int>();
- if (closed) return _completeWithClosedException(completer);
+ if (closed) return _closedException();
List request = new List(2);
request[0] = _READ_BYTE_REQUEST;
request[1] = _id;
@@ -631,18 +645,11 @@
Future<List<int>> read(int bytes) {
_ensureFileService();
- Completer<List<int>> completer = new Completer<List<int>>();
if (bytes is !int) {
- // Complete asynchronously so the user has a chance to setup
- // handlers without getting exceptions when registering the
- // then handler.
- Timer.run(() {
- completer.completeError(new FileIOException(
- "Invalid arguments to read for file '$_path'"));
- });
- return completer.future;
- };
- if (closed) return _completeWithClosedException(completer);
+ return new Future.error(new FileIOException(
+ "Invalid arguments to read for file '$_path'"));
+ }
+ if (closed) return _closedException();
List request = new List(3);
request[0] = _READ_REQUEST;
request[1] = _id;
@@ -680,8 +687,7 @@
return new Future.error(new FileIOException(
"Invalid arguments to readInto for file '$_path'"));
};
- Completer<int> completer = new Completer<int>();
- if (closed) return _completeWithClosedException(completer);
+ if (closed) return _closedException();
List request = new List(3);
if (start == null) start = 0;
if (end == null) end = buffer.length;
@@ -732,18 +738,11 @@
Future<RandomAccessFile> writeByte(int value) {
_ensureFileService();
- Completer<RandomAccessFile> completer = new Completer<RandomAccessFile>();
if (value is !int) {
- // Complete asynchronously so the user has a chance to setup
- // handlers without getting exceptions when registering the
- // then handler.
- Timer.run(() {
- completer.completeError(new FileIOException(
- "Invalid argument to writeByte for file '$_path'"));
- });
- return completer.future;
+ return new Future.error(new FileIOException(
+ "Invalid argument to writeByte for file '$_path'"));
}
- if (closed) return _completeWithClosedException(completer);
+ if (closed) return _closedException();
List request = new List(3);
request[0] = _WRITE_BYTE_REQUEST;
request[1] = _id;
@@ -781,9 +780,8 @@
return new Future.error(new FileIOException(
"Invalid arguments to writeFrom for file '$_path'"));
}
- Completer<RandomAccessFile> completer = new Completer<RandomAccessFile>();
- if (closed) return _completeWithClosedException(completer);
+ if (closed) return _closedException();
_BufferAndStart result;
try {
@@ -835,12 +833,8 @@
Future<RandomAccessFile> writeString(String string,
{Encoding encoding: Encoding.UTF_8}) {
if (encoding is! Encoding) {
- var completer = new Completer();
- Timer.run(() {
- completer.completeError(new FileIOException(
- "Invalid encoding in writeString: $encoding"));
- });
- return completer.future;
+ return new Future.error(new FileIOException(
+ "Invalid encoding in writeString: $encoding"));
}
var data = _encodeString(string, encoding);
return writeFrom(data, 0, data.length);
@@ -857,8 +851,7 @@
Future<int> position() {
_ensureFileService();
- Completer<int> completer = new Completer<int>();
- if (closed) return _completeWithClosedException(completer);
+ if (closed) return _closedException();
List request = new List(2);
request[0] = _POSITION_REQUEST;
request[1] = _id;
@@ -884,8 +877,7 @@
Future<RandomAccessFile> setPosition(int position) {
_ensureFileService();
- Completer<RandomAccessFile> completer = new Completer<RandomAccessFile>();
- if (closed) return _completeWithClosedException(completer);
+ if (closed) return _closedException();
List request = new List(3);
request[0] = _SET_POSITION_REQUEST;
request[1] = _id;
@@ -911,8 +903,7 @@
Future<RandomAccessFile> truncate(int length) {
_ensureFileService();
- Completer<RandomAccessFile> completer = new Completer<RandomAccessFile>();
- if (closed) return _completeWithClosedException(completer);
+ if (closed) return _closedException();
List request = new List(3);
request[0] = _TRUNCATE_REQUEST;
request[1] = _id;
@@ -938,8 +929,7 @@
Future<int> length() {
_ensureFileService();
- Completer<int> completer = new Completer<int>();
- if (closed) return _completeWithClosedException(completer);
+ if (closed) return _closedException();
List request = new List(2);
request[0] = _LENGTH_REQUEST;
request[1] = _id;
@@ -965,8 +955,7 @@
Future<RandomAccessFile> flush() {
_ensureFileService();
- Completer<RandomAccessFile> completer = new Completer<RandomAccessFile>();
- if (closed) return _completeWithClosedException(completer);
+ if (closed) return _closedException();
List request = new List(2);
request[0] = _FLUSH_REQUEST;
request[1] = _id;
@@ -1005,12 +994,8 @@
}
}
- Future _completeWithClosedException(Completer completer) {
- Timer.run(() {
- completer.completeError(
- new FileIOException("File closed '$_path'"));
- });
- return completer.future;
+ Future _closedException() {
+ return new Future.error(new FileIOException("File closed '$_path'"));
}
final String _path;
diff --git a/sdk/lib/io/http.dart b/sdk/lib/io/http.dart
index 47be232..5dc5738 100644
--- a/sdk/lib/io/http.dart
+++ b/sdk/lib/io/http.dart
@@ -873,6 +873,12 @@
static const int DEFAULT_HTTP_PORT = 80;
static const int DEFAULT_HTTPS_PORT = 443;
+ /**
+ * Get and set the idle timeout of non-active persistent (keep-alive)
+ * connections. The default value is 15 seconds.
+ */
+ Duration idleTimeout;
+
factory HttpClient() => new _HttpClient();
/**
diff --git a/sdk/lib/io/http_headers.dart b/sdk/lib/io/http_headers.dart
index 8153850..cabdfb0 100644
--- a/sdk/lib/io/http_headers.dart
+++ b/sdk/lib/io/http_headers.dart
@@ -23,7 +23,7 @@
return values[0];
}
- void add(String name, Object value) {
+ void add(String name, value) {
_checkMutable();
if (value is List) {
for (int i = 0; i < value.length; i++) {
diff --git a/sdk/lib/io/http_impl.dart b/sdk/lib/io/http_impl.dart
index 73acb00..c749ceb 100644
--- a/sdk/lib/io/http_impl.dart
+++ b/sdk/lib/io/http_impl.dart
@@ -47,9 +47,9 @@
// Is completed once all data have been received.
Future get dataDone => _dataCompleter.future;
- void close() {
+ void close(bool closing) {
fullBodyRead = true;
- _dataCompleter.complete();
+ _dataCompleter.complete(closing);
}
}
@@ -580,13 +580,12 @@
bool _done([error]) {
if (_completer == null) return false;
- var tmp = _completer;
- _completer = null;
if (error != null) {
- tmp.completeError(error);
+ _completer.completeError(error);
} else {
- tmp.complete(_outbound);
+ _completer.complete(_outbound);
}
+ _completer = null;
return true;
}
@@ -1071,6 +1070,7 @@
StreamSubscription _subscription;
final _HttpClient _httpClient;
bool _dispose = false;
+ Timer _idleTimer;
bool closed = false;
Completer<_HttpIncoming> _nextResponseCompleter;
@@ -1285,6 +1285,22 @@
return isSecure ? "ssh:$host:$port" : "$host:$port";
}
+ void stopTimer() {
+ if (_idleTimer != null) {
+ _idleTimer.cancel();
+ _idleTimer = null;
+ }
+ }
+
+ void startTimer() {
+ assert(_idleTimer == null);
+ _idleTimer = new Timer(
+ _httpClient.idleTimeout,
+ () {
+ _idleTimer = null;
+ close();
+ });
+ }
}
class _ConnnectionInfo {
@@ -1296,7 +1312,6 @@
class _HttpClient implements HttpClient {
// TODO(ajohnsen): Use eviction timeout.
- static const int DEFAULT_EVICTION_TIMEOUT = 60000;
bool _closing = false;
final Map<String, Set<_HttpClientConnection>> _idleConnections
@@ -1308,6 +1323,21 @@
Function _authenticate;
Function _authenticateProxy;
Function _findProxy = HttpClient.findProxyFromEnvironment;
+ Duration _idleTimeout = const Duration(seconds: 15);
+
+ Timer _noActiveTimer;
+
+ Duration get idleTimeout => _idleTimeout;
+
+ void set idleTimeout(Duration timeout) {
+ _idleTimeout = timeout;
+ _idleConnections.values.forEach(
+ (l) => l.forEach((c) {
+ // Reset timer. This is fine, as it's not happening often.
+ c.stopTimer();
+ c.startTimer();
+ }));
+ }
Future<HttpClientRequest> open(String method,
String host,
@@ -1485,15 +1515,17 @@
connection.close();
return;
}
- // TODO(ajohnsen): Listen for socket close events.
if (!_idleConnections.containsKey(connection.key)) {
_idleConnections[connection.key] = new LinkedHashSet();
}
_idleConnections[connection.key].add(connection);
+ connection.startTimer();
+ _updateTimers();
}
// Remove a closed connnection from the active set.
void _connectionClosed(_HttpClientConnection connection) {
+ connection.stopTimer();
_activeConnections.remove(connection);
if (_idleConnections.containsKey(connection.key)) {
_idleConnections[connection.key].remove(connection);
@@ -1501,6 +1533,24 @@
_idleConnections.remove(connection.key);
}
}
+ _updateTimers();
+ }
+
+ void _updateTimers() {
+ if (_activeConnections.isEmpty) {
+ if (!_idleConnections.isEmpty && _noActiveTimer == null) {
+ _noActiveTimer = new Timer(const Duration(milliseconds: 100), () {
+ _noActiveTimer = null;
+ if (_activeConnections.isEmpty) {
+ close();
+ _closing = false;
+ }
+ });
+ }
+ } else if (_noActiveTimer != null) {
+ _noActiveTimer.cancel();
+ _noActiveTimer = null;
+ }
}
// Get a new _HttpClientConnection, either from the idle pool or created from
@@ -1523,7 +1573,9 @@
if (_idleConnections[key].isEmpty) {
_idleConnections.remove(key);
}
+ connection.stopTimer();
_activeConnections.add(connection);
+ _updateTimers();
return new Future.value(new _ConnnectionInfo(connection, proxy));
}
return (isSecure && proxy.isDirect
@@ -1668,6 +1720,10 @@
_socket.pipe(_httpParser);
_subscription = _httpParser.listen(
(incoming) {
+ // If the incoming was closed, close the connection.
+ incoming.dataDone.then((closing) {
+ if (closing) destroy();
+ });
// Only handle one incoming request at the time. Keep the
// stream paused until the request has been send.
_subscription.pause();
diff --git a/sdk/lib/io/http_parser.dart b/sdk/lib/io/http_parser.dart
index af937e9..58622cf 100644
--- a/sdk/lib/io/http_parser.dart
+++ b/sdk/lib/io/http_parser.dart
@@ -105,8 +105,7 @@
Completer resumeCompleter;
_HttpDetachedIncoming(StreamSubscription this.subscription,
- List<int> this.carryOverData,
- Completer oldResumeCompleter) {
+ List<int> this.carryOverData) {
controller = new StreamController<List<int>>(
onListen: resume,
onPause: pause,
@@ -118,7 +117,6 @@
controller.close();
} else {
pause();
- if (oldResumeCompleter != null) oldResumeCompleter.complete();
subscription.resume();
subscription.onData(controller.add);
subscription.onDone(controller.close);
@@ -729,7 +727,7 @@
new HttpParserException(
"Connection closed while receiving data"));
}
- _closeIncoming();
+ _closeIncoming(true);
_controller.close();
return;
}
@@ -792,11 +790,8 @@
void set responseToMethod(String method) { _responseToMethod = method; }
_HttpDetachedIncoming detachIncoming() {
- var completer = _pauseCompleter;
- _pauseCompleter = null;
return new _HttpDetachedIncoming(_socketSubscription,
- readUnparsedData(),
- completer);
+ readUnparsedData());
}
List<int> readUnparsedData() {
@@ -909,7 +904,7 @@
if (_socketSubscription != null) {
_socketSubscription.cancel();
}
- _closeIncoming();
+ _closeIncoming(true);
_controller.close();
});
incoming = _incoming = new _HttpIncoming(
@@ -918,11 +913,11 @@
_pauseStateChanged();
}
- void _closeIncoming() {
+ void _closeIncoming([bool closing = false]) {
// Ignore multiple close (can happend in re-entrance).
if (_incoming == null) return;
var tmp = _incoming;
- tmp.close();
+ tmp.close(closing);
_incoming = null;
if (_bodyController != null) {
_bodyController.close();
@@ -993,7 +988,6 @@
StreamSubscription _socketSubscription;
bool _paused = true;
bool _bodyPaused = false;
- Completer _pauseCompleter;
StreamController<_HttpIncoming> _controller;
StreamController<List<int>> _bodyController;
}
diff --git a/sdk/lib/io/io.dart b/sdk/lib/io/io.dart
index fee6a12..c44f6ba 100644
--- a/sdk/lib/io/io.dart
+++ b/sdk/lib/io/io.dart
@@ -25,7 +25,6 @@
import 'dart:utf';
import 'dart:typed_data';
-part 'base64.dart';
part 'buffer_list.dart';
part 'common.dart';
part 'data_transformer.dart';
diff --git a/sdk/lib/io/io_sink.dart b/sdk/lib/io/io_sink.dart
index c6a82f0..8e8b71f 100644
--- a/sdk/lib/io/io_sink.dart
+++ b/sdk/lib/io/io_sink.dart
@@ -116,13 +116,12 @@
void _completeDone({value, error}) {
if (_doneCompleter == null) return;
- var tmp = _doneCompleter;
- _doneCompleter = null;
if (error == null) {
- tmp.complete(value);
+ _doneCompleter.complete(value);
} else {
- tmp.completeError(error);
+ _doneCompleter.completeError(error);
}
+ _doneCompleter = null;
}
StreamController<T> get _controller {
@@ -140,10 +139,9 @@
(_) {
if (_isBound) {
// A new stream takes over - forward values to that stream.
- var completer = _controllerCompleter;
+ _controllerCompleter.complete();
_controllerCompleter = null;
_controllerInstance = null;
- completer.complete();
} else {
// No new stream, .close was called. Close _target.
_closeTarget();
@@ -152,10 +150,9 @@
onError: (error) {
if (_isBound) {
// A new stream takes over - forward errors to that stream.
- var completer = _controllerCompleter;
+ _controllerCompleter.completeError(error);
_controllerCompleter = null;
_controllerInstance = null;
- completer.completeError(error);
} else {
// No new stream. No need to close target, as it have already
// failed.
diff --git a/sdk/lib/io/iolib_sources.gypi b/sdk/lib/io/iolib_sources.gypi
index 2eab1d9..5225dc1 100644
--- a/sdk/lib/io/iolib_sources.gypi
+++ b/sdk/lib/io/iolib_sources.gypi
@@ -4,7 +4,6 @@
{
'sources': [
- 'base64.dart',
'buffer_list.dart',
'common.dart',
'data_transformer.dart',
diff --git a/sdk/lib/io/process.dart b/sdk/lib/io/process.dart
index c1a060a..6e9b1cd 100644
--- a/sdk/lib/io/process.dart
+++ b/sdk/lib/io/process.dart
@@ -100,6 +100,57 @@
[ProcessOptions options]);
/**
+ * Starts a process in the system shell and runs it non-interactively to
+ * completion.
+ *
+ * On Linux and Mac OS, [:/bin/sh:] is used to execute the [executable].
+ * On Windows, [:%WINDIR%\system32\cmd.exe:] is used.
+ *
+ * An optional [ProcessOptions] object can be passed to specify
+ * options other than the executable and the arguments.
+ *
+ * Returns a [:Future<ProcessResult>:] that completes with the
+ * result of running the process, i.e., exit code, standard out and
+ * standard in.
+ */
+ static Future<ProcessResult> runShell(String executable,
+ List<String> arguments,
+ [ProcessOptions options])
+ => run(_getShellCommand(),
+ _getShellArguments(executable, arguments),
+ options);
+
+ static String _getShellCommand() {
+ if (Platform.operatingSystem == 'windows') {
+ return 'cmd.exe';
+ }
+ return '/bin/sh';
+ }
+
+ static List<String> _getShellArguments(String executable,
+ List<String> arguments) {
+ List<String> shellArguments = [];
+ if (Platform.operatingSystem == 'windows') {
+ shellArguments.add('/c');
+ shellArguments.add(executable);
+ for (var arg in arguments) {
+ arg = arg.replaceAll('"', r'\"');
+ shellArguments.add(arg);
+ }
+ } else {
+ var commandLine = new StringBuffer();
+ commandLine.write(executable);
+ shellArguments.add("-c");
+ for (var arg in arguments) {
+ arg = arg.replaceAll("'", "'\"'\"'");
+ commandLine.write(" '$arg'");
+ }
+ shellArguments.add(commandLine.toString());
+ }
+ return shellArguments;
+ }
+
+ /**
* Returns the standard output stream of the process as a [:Stream:].
*
* Throws an [UnsupportedError] if the process is
diff --git a/sdk/lib/io/websocket_impl.dart b/sdk/lib/io/websocket_impl.dart
index 74df425..3cef0ad 100644
--- a/sdk/lib/io/websocket_impl.dart
+++ b/sdk/lib/io/websocket_impl.dart
@@ -408,7 +408,7 @@
String key = request.headers.value("Sec-WebSocket-Key");
SHA1 sha1 = new SHA1();
sha1.add("$key$_webSocketGUID".codeUnits);
- String accept = _Base64._encode(sha1.close());
+ String accept = CryptoUtils.bytesToBase64(sha1.close());
response.headers.add("Sec-WebSocket-Accept", accept);
response.headers.contentLength = 0;
return response.detachSocket()
@@ -585,13 +585,12 @@
bool _done([error]) {
if (_completer == null) return false;
- var tmp = _completer;
- _completer = null;
if (error != null) {
- tmp.completeError(error);
+ _completer.completeError(error);
} else {
- tmp.complete(webSocket);
+ _completer.complete(webSocket);
}
+ _completer = null;
return true;
}
@@ -659,7 +658,7 @@
for (int i = 0; i < 16; i++) {
nonceData[i] = random.nextInt(256);
}
- String nonce = _Base64._encode(nonceData);
+ String nonce = CryptoUtils.bytesToBase64(nonceData);
uri = new Uri.fromComponents(scheme: uri.scheme == "wss" ? "https" : "http",
userInfo: uri.userInfo,
@@ -700,7 +699,7 @@
SHA1 sha1 = new SHA1();
sha1.add("$nonce$_webSocketGUID".codeUnits);
List<int> expectedAccept = sha1.close();
- List<int> receivedAccept = _Base64._decode(accept);
+ List<int> receivedAccept = CryptoUtils.base64StringToBytes(accept);
if (expectedAccept.length != receivedAccept.length) {
error("Reasponse header 'Sec-WebSocket-Accept' is the wrong length");
}
diff --git a/sdk/lib/svg/dart2js/svg_dart2js.dart b/sdk/lib/svg/dart2js/svg_dart2js.dart
index ae4f720..564670f 100644
--- a/sdk/lib/svg/dart2js/svg_dart2js.dart
+++ b/sdk/lib/svg/dart2js/svg_dart2js.dart
@@ -5365,7 +5365,7 @@
return _cssClassSet;
}
- List<Element> get children => new FilteredElementList(this);
+ List<Element> get children => new FilteredElementList<Element>(this);
void set children(List<Element> value) {
final children = this.children;
diff --git a/sdk/lib/svg/dartium/svg_dartium.dart b/sdk/lib/svg/dartium/svg_dartium.dart
index bb2ad9b..d8d92c2 100644
--- a/sdk/lib/svg/dartium/svg_dartium.dart
+++ b/sdk/lib/svg/dartium/svg_dartium.dart
@@ -6110,7 +6110,7 @@
return _cssClassSet;
}
- List<Element> get children => new FilteredElementList(this);
+ List<Element> get children => new FilteredElementList<Element>(this);
void set children(List<Element> value) {
final children = this.children;
diff --git a/tests/co19/co19-analyzer.status b/tests/co19/co19-analyzer.status
index 814b54d..2a350af 100644
--- a/tests/co19/co19-analyzer.status
+++ b/tests/co19/co19-analyzer.status
@@ -3,16 +3,7 @@
# BSD-style license that can be found in the LICENSE file.
[ $compiler == dartanalyzer ]
-Language/03_Overview/1_Scoping_A01_t46: fail
-Language/03_Overview/1_Scoping_A02_t07: fail
-Language/03_Overview/1_Scoping_A02_t11: fail
-Language/03_Overview/1_Scoping_A02_t12: fail
-Language/03_Overview/1_Scoping_A02_t16: fail
-Language/03_Overview/1_Scoping_A02_t28: fail
-Language/05_Variables/05_Variables_A01_t09: fail
-Language/05_Variables/05_Variables_A01_t11: fail
Language/05_Variables/05_Variables_A05_t04: fail
-Language/06_Functions/06_Functions_A01_t10: fail
Language/06_Functions/06_Functions_A01_t31: fail
Language/06_Functions/2_Formal_Parameters/1_Required_Formals_A02_t06: fail
Language/06_Functions/2_Formal_Parameters/1_Required_Formals_A02_t07: fail
@@ -20,11 +11,7 @@
Language/06_Functions/2_Formal_Parameters_A01_t02: fail
Language/06_Functions/2_Formal_Parameters_A01_t09: fail
Language/06_Functions/2_Formal_Parameters_A02_t02: fail
-Language/07_Classes/07_Classes_A02_t02: fail
-Language/07_Classes/07_Classes_A02_t04: fail
-Language/07_Classes/07_Classes_A03_t02: fail
-Language/07_Classes/07_Classes_A03_t07: fail
-Language/07_Classes/07_Classes_A03_t08: fail
+Language/07_Classes/07_Classes_A01_t20: fail
Language/07_Classes/07_Classes_A09_t01: fail
Language/07_Classes/07_Classes_A09_t02: fail
Language/07_Classes/07_Classes_A09_t03: fail
@@ -37,19 +24,15 @@
Language/07_Classes/3_Setters_A03_t04: fail
Language/07_Classes/3_Setters_A03_t06: fail
Language/07_Classes/3_Setters_A03_t08: fail
-Language/07_Classes/6_Constructors/1_Generative_Constructors_A03_t04: fail
-Language/07_Classes/6_Constructors/1_Generative_Constructors_A03_t06: fail
-Language/07_Classes/6_Constructors/1_Generative_Constructors_A03_t11: fail
Language/07_Classes/6_Constructors/1_Generative_Constructors_A04_t15: fail
Language/07_Classes/6_Constructors/1_Generative_Constructors_A09_t01: fail
-Language/07_Classes/6_Constructors/1_Generative_Constructors_A11_t04: fail
-Language/07_Classes/6_Constructors/1_Generative_Constructors_A11_t06: fail
-Language/07_Classes/6_Constructors/1_Generative_Constructors_A11_t07: fail
Language/07_Classes/6_Constructors/1_Generative_Constructors_A11_t09: fail
Language/07_Classes/6_Constructors/1_Generative_Constructors_A14_t01: fail
Language/07_Classes/6_Constructors/1_Generative_Constructors_A14_t04: fail
Language/07_Classes/6_Constructors/1_Generative_Constructors_A15_t07: fail
-Language/07_Classes/6_Constructors/3_Constant_Constructors_A03_t02: fail
+Language/07_Classes/6_Constructors/2_Factories_A06_t01: fail
+Language/07_Classes/6_Constructors/2_Factories_A06_t02: fail
+Language/07_Classes/6_Constructors/2_Factories_A06_t04: fail
Language/07_Classes/6_Constructors/3_Constant_Constructors_A04_t01: fail
Language/07_Classes/6_Constructors/3_Constant_Constructors_A05_t01: fail
Language/07_Classes/6_Constructors/3_Constant_Constructors_A05_t02: fail
@@ -60,6 +43,7 @@
Language/08_Interfaces/5_Superinterfaces_A01_t03: fail
Language/08_Interfaces/5_Superinterfaces_A01_t04: fail
Language/08_Interfaces/5_Superinterfaces_A04_t03: fail
+Language/09_Generics/09_Generics_A04_t07: fail
Language/11_Expressions/01_Constants_A01_t01: fail
Language/11_Expressions/01_Constants_A08_t02: fail
Language/11_Expressions/01_Constants_A09_t02: fail
@@ -78,20 +62,12 @@
Language/11_Expressions/03_Numbers_A01_t04: fail
Language/11_Expressions/03_Numbers_A01_t08: fail
Language/11_Expressions/03_Numbers_A01_t10: fail
-Language/11_Expressions/05_Strings/1_String_Interpolation_A01_t03: fail
-Language/11_Expressions/05_Strings/1_String_Interpolation_A01_t09: fail
-Language/11_Expressions/05_Strings/1_String_Interpolation_A01_t11: fail
-Language/11_Expressions/05_Strings/1_String_Interpolation_A01_t14: fail
-Language/11_Expressions/05_Strings/1_String_Interpolation_A01_t15: fail
-Language/11_Expressions/05_Strings_A02_t34: fail
-Language/11_Expressions/05_Strings_A02_t36: fail
-Language/11_Expressions/05_Strings_A02_t42: fail
-Language/11_Expressions/05_Strings_A02_t44: fail
+Language/11_Expressions/05_Strings/1_String_Interpolation_A03_t01: fail
+Language/11_Expressions/05_Strings/1_String_Interpolation_A04_t01: fail
Language/11_Expressions/05_Strings_A02_t46: fail
Language/11_Expressions/05_Strings_A02_t48: fail
-Language/11_Expressions/06_Lists_A01_t03: fail
-Language/11_Expressions/06_Lists_A01_t04: fail
Language/11_Expressions/06_Lists_A03_t01: fail
+Language/11_Expressions/06_Lists_A06_t01: fail
Language/11_Expressions/07_Maps_A02_t02: fail
Language/11_Expressions/08_Throw_A06_t01: fail
Language/11_Expressions/08_Throw_A06_t02: fail
@@ -99,110 +75,41 @@
Language/11_Expressions/08_Throw_A06_t04: fail
Language/11_Expressions/08_Throw_A06_t05: fail
Language/11_Expressions/08_Throw_A06_t06: fail
-Language/11_Expressions/11_Instance_Creation/1_New_A01_t04: fail
+Language/11_Expressions/11_Instance_Creation/1_New_A13_t02: fail
Language/11_Expressions/11_Instance_Creation/2_Const_A06_t01: fail
Language/11_Expressions/11_Instance_Creation/2_Const_A06_t02: fail
Language/11_Expressions/11_Instance_Creation/2_Const_A10_t01: fail
Language/11_Expressions/11_Instance_Creation_A05_t02: fail
-Language/11_Expressions/14_Function_Invocation/1_Actual_Argument_List_Evaluation_A01_t05: fail
+Language/11_Expressions/14_Function_Invocation/1_Actual_Argument_List_Evaluation_A02_t01: fail
Language/11_Expressions/14_Function_Invocation/2_Binding_Actuals_to_Formals_A04_t01: fail
-Language/11_Expressions/14_Function_Invocation/3_Unqualified_Invocation_A01_t10: fail
-Language/11_Expressions/15_Method_Invocation/1_Ordinary_Invocation_A01_t05: fail
-Language/11_Expressions/15_Method_Invocation/3_Static_Invocation_A01_t05: fail
-Language/11_Expressions/15_Method_Invocation/4_Super_Invocation_A01_t05: fail
-Language/11_Expressions/19_Conditional_A01_t05: fail
-Language/11_Expressions/19_Conditional_A01_t06: fail
-Language/11_Expressions/20_Logical_Boolean_Expressions_A01_t04: fail
-Language/11_Expressions/20_Logical_Boolean_Expressions_A01_t05: fail
-Language/11_Expressions/20_Logical_Boolean_Expressions_A01_t06: fail
-Language/11_Expressions/20_Logical_Boolean_Expressions_A01_t07: fail
-Language/11_Expressions/20_Logical_Boolean_Expressions_A01_t08: fail
-Language/11_Expressions/20_Logical_Boolean_Expressions_A01_t09: fail
-Language/11_Expressions/21_Bitwise_Expressions_A01_t03: fail
-Language/11_Expressions/21_Bitwise_Expressions_A01_t04: fail
-Language/11_Expressions/21_Bitwise_Expressions_A01_t05: fail
-Language/11_Expressions/21_Bitwise_Expressions_A01_t06: fail
-Language/11_Expressions/21_Bitwise_Expressions_A01_t07: fail
-Language/11_Expressions/21_Bitwise_Expressions_A01_t08: fail
-Language/11_Expressions/21_Bitwise_Expressions_A01_t09: fail
-Language/11_Expressions/21_Bitwise_Expressions_A01_t10: fail
-Language/11_Expressions/21_Bitwise_Expressions_A01_t11: fail
-Language/11_Expressions/22_Equality_A01_t03: fail
-Language/11_Expressions/22_Equality_A01_t04: fail
-Language/11_Expressions/22_Equality_A01_t07: fail
-Language/11_Expressions/22_Equality_A01_t08: fail
-Language/11_Expressions/22_Equality_A01_t11: fail
-Language/11_Expressions/22_Equality_A01_t12: fail
+Language/11_Expressions/14_Function_Invocation/3_Unqualified_Invocation_A01_t05: fail
+Language/11_Expressions/14_Function_Invocation/4_Function_Expression_Invocation_A02_t01: fail
+Language/11_Expressions/14_Function_Invocation/4_Function_Expression_Invocation_A05_t01: fail
+Language/11_Expressions/15_Method_Invocation/1_Ordinary_Invocation_A04_t01: fail
+Language/11_Expressions/15_Method_Invocation/1_Ordinary_Invocation_A08_t01: fail
+Language/11_Expressions/15_Method_Invocation/3_Static_Invocation_A03_t01: fail
+Language/11_Expressions/15_Method_Invocation/3_Static_Invocation_A03_t07: fail
+Language/11_Expressions/15_Method_Invocation/3_Static_Invocation_A04_t05: fail
+Language/11_Expressions/15_Method_Invocation/3_Static_Invocation_A06_t02: fail
+Language/11_Expressions/15_Method_Invocation/4_Super_Invocation_A02_t04: fail
+Language/11_Expressions/15_Method_Invocation/4_Super_Invocation_A03_t01: fail
+Language/11_Expressions/15_Method_Invocation/4_Super_Invocation_A03_t02: fail
+Language/11_Expressions/15_Method_Invocation/4_Super_Invocation_A03_t03: fail
+Language/11_Expressions/15_Method_Invocation/4_Super_Invocation_A03_t04: fail
+Language/11_Expressions/15_Method_Invocation/4_Super_Invocation_A08_t02: fail
Language/11_Expressions/22_Equality_A01_t15: fail
Language/11_Expressions/22_Equality_A01_t16: fail
-Language/11_Expressions/23_Relational_Expressions_A01_t03: fail
-Language/11_Expressions/23_Relational_Expressions_A01_t04: fail
-Language/11_Expressions/23_Relational_Expressions_A01_t05: fail
-Language/11_Expressions/23_Relational_Expressions_A01_t06: fail
-Language/11_Expressions/23_Relational_Expressions_A01_t07: fail
-Language/11_Expressions/23_Relational_Expressions_A01_t08: fail
-Language/11_Expressions/23_Relational_Expressions_A01_t09: fail
-Language/11_Expressions/24_Shift_A01_t02: fail
-Language/11_Expressions/24_Shift_A01_t03: fail
-Language/11_Expressions/24_Shift_A01_t04: fail
-Language/11_Expressions/24_Shift_A01_t05: fail
-Language/11_Expressions/24_Shift_A01_t06: fail
-Language/11_Expressions/24_Shift_A01_t07: fail
-Language/11_Expressions/25_Additive_Expressions_A01_t02: fail
-Language/11_Expressions/25_Additive_Expressions_A01_t03: fail
-Language/11_Expressions/25_Additive_Expressions_A01_t06: fail
-Language/11_Expressions/26_Multiplicative_Expressions_A01_t02: fail
-Language/11_Expressions/26_Multiplicative_Expressions_A01_t03: fail
-Language/11_Expressions/26_Multiplicative_Expressions_A01_t04: fail
-Language/11_Expressions/26_Multiplicative_Expressions_A01_t05: fail
-Language/11_Expressions/26_Multiplicative_Expressions_A01_t06: fail
-Language/11_Expressions/26_Multiplicative_Expressions_A01_t07: fail
-Language/11_Expressions/26_Multiplicative_Expressions_A01_t08: fail
-Language/11_Expressions/26_Multiplicative_Expressions_A01_t18: fail
-Language/11_Expressions/26_Multiplicative_Expressions_A01_t19: fail
-Language/11_Expressions/26_Multiplicative_Expressions_A01_t20: fail
-Language/11_Expressions/26_Multiplicative_Expressions_A01_t21: fail
-Language/11_Expressions/26_Multiplicative_Expressions_A01_t22: fail
-Language/11_Expressions/26_Multiplicative_Expressions_A01_t23: fail
-Language/11_Expressions/26_Multiplicative_Expressions_A01_t24: fail
-Language/11_Expressions/26_Multiplicative_Expressions_A01_t25: fail
-Language/11_Expressions/27_Unary_Expressions_A01_t08: fail
Language/11_Expressions/28_Postfix_Expressions_A01_t06: fail
-Language/11_Expressions/28_Postfix_Expressions_A01_t09: fail
-Language/11_Expressions/28_Postfix_Expressions_A01_t10: fail
-Language/11_Expressions/28_Postfix_Expressions_A01_t11: fail
-Language/11_Expressions/29_Assignable_Expressions_A01_t10: fail
-Language/11_Expressions/29_Assignable_Expressions_A01_t11: fail
-Language/11_Expressions/29_Assignable_Expressions_A01_t12: fail
-Language/11_Expressions/29_Assignable_Expressions_A01_t13: fail
-Language/11_Expressions/29_Assignable_Expressions_A01_t15: fail
-Language/11_Expressions/29_Assignable_Expressions_A01_t16: fail
Language/11_Expressions/30_Identifier_Reference_A01_t07: fail
Language/11_Expressions/30_Identifier_Reference_A01_t08: fail
-Language/11_Expressions/31_Type_Test_A05_t01: fail
-Language/11_Expressions/31_Type_Test_A05_t02: fail
-Language/11_Expressions/31_Type_Test_A05_t03: fail
-Language/11_Expressions/32_Type_Cast_A04_t01: fail
-Language/11_Expressions/32_Type_Cast_A04_t02: fail
Language/11_Expressions/33_Argument_Definition_Test_A01_t14: fail
Language/11_Expressions/33_Argument_Definition_Test_A01_t18: fail
Language/12_Statements/02_Expression_Statements_A01_t06: fail
-Language/12_Statements/02_Expression_Statements_A01_t12: fail
-Language/12_Statements/04_Local_Function_Declaration_A01_t01: fail
-Language/12_Statements/04_Local_Function_Declaration_A02_t02: fail
-Language/12_Statements/05_If_A01_t01: fail
-Language/12_Statements/06_For_A01_t10: fail
-Language/12_Statements/07_While_A01_t04: fail
-Language/12_Statements/08_Do_A01_t07: fail
-Language/12_Statements/09_Switch_A01_t06: fail
Language/12_Statements/09_Switch_A04_t01: fail
-Language/12_Statements/15_Assert_A01_t03: fail
Language/13_Libraries_and_Scripts/13_Libraries_and_Scripts_A03_t17: fail
Language/13_Libraries_and_Scripts/1_Imports_A01_t46: fail
-Language/13_Libraries_and_Scripts/1_Imports_A02_t12: fail
-Language/13_Libraries_and_Scripts/1_Imports_A02_t15: fail
Language/13_Libraries_and_Scripts/1_Imports_A04_t03: fail
-Language/13_Libraries_and_Scripts/1_Imports_A05_t01: fail # co19 issue 411
+Language/13_Libraries_and_Scripts/1_Imports_A05_t01: fail
Language/13_Libraries_and_Scripts/2_Exports_A05_t01: fail
Language/13_Libraries_and_Scripts/5_URIs_A01_t24: fail
Language/13_Libraries_and_Scripts/5_URIs_A01_t25: fail
@@ -210,15 +117,82 @@
Language/14_Types/3_Type_Declarations/1_Typedef_A07_t02: fail
Language/14_Types/3_Type_Declarations/1_Typedef_A07_t03: fail
Language/14_Types/3_Type_Declarations/1_Typedef_A07_t04: fail
+Language/14_Types/4_Interface_Types_A10_t03: fail
+Language/14_Types/4_Interface_Types_A10_t04: fail
+Language/14_Types/4_Interface_Types_A10_t09: fail
Language/15_Reference/1_Lexical_Rules/1_Reserved_Words_A40_t04: fail
+Language/15_Reference/1_Lexical_Rules_A01_t10: fail
Language/15_Reference/1_Lexical_Rules_A02_t06: fail
+LibTest/core/AssertionError/column_A01_t02: fail
+LibTest/core/AssertionError/failedAssertion_A01_t01: fail
+LibTest/core/AssertionError/line_A01_t02: fail
+LibTest/core/AssertionError/url_A01_t01: fail
+LibTest/core/Iterable/where_A01_t07: fail
+LibTest/core/List/List.fixedLength_A01_t01: fail
+LibTest/core/List/List_A01_t02: fail
+LibTest/core/List/addLast_A01_t01: fail
+LibTest/core/List/addLast_A01_t03: fail
+LibTest/core/List/addLast_A02_t01: fail
+LibTest/core/List/every_A01_t01: fail
+LibTest/core/List/insertRange_A01_t01: fail
+LibTest/core/List/insertRange_A02_t01: fail
+LibTest/core/List/insertRange_A03_t01: fail
+LibTest/core/List/insertRange_A04_t01: fail
+LibTest/core/List/insertRange_A05_t01: fail
+LibTest/core/List/insertRange_A06_t01: fail
+LibTest/core/List/insertRange_A07_t01: fail
+LibTest/core/List/insertRange_A08_t01: fail
+LibTest/core/RegExp/Pattern_semantics/firstMatch_Atom_A03_t02: fail
+LibTest/core/RegExp/Pattern_semantics/firstMatch_Atom_A04_t01: fail
+LibTest/core/RegExp/Pattern_semantics/firstMatch_CharacterClassEscape_A03_t01: fail
+LibTest/core/RegExp/Pattern_semantics/firstMatch_CharacterClassEscape_A04_t01: fail
+LibTest/core/RegExp/Pattern_semantics/firstMatch_CharacterEscape_A06_t02: fail
+LibTest/core/RegExp/Pattern_semantics/firstMatch_CharacterEscape_A07_t01: fail
+LibTest/core/RegExp/Pattern_semantics/firstMatch_CharacterEscape_A08_t01: fail
+LibTest/core/RegExp/Pattern_semantics/firstMatch_CharacterEscape_A08_t02: fail
+LibTest/core/RegExp/Pattern_semantics/firstMatch_CharacterEscape_A09_t01: fail
+LibTest/core/Set/isSubsetOf_A01_t01: fail
+LibTest/core/Set/isSubsetOf_A01_t02: fail
+LibTest/core/String/String_class_A01_t01: fail
+LibTest/core/String/charCodeAt_A01_t01: fail
+LibTest/core/String/charCodeAt_A02_t01: fail
+LibTest/core/String/charCodeAt_A03_t01: fail
+LibTest/core/String/charCodes_A01_t01: fail
+LibTest/core/String/concat_A01_t01: fail
+LibTest/core/String/concat_A02_t01: fail
+LibTest/core/String/hashCode_A01_t01: fail
+LibTest/core/String/splitChars_A01_t01: fail
+LibTest/core/StringBuffer/addAll_A01_t01: fail
+LibTest/core/StringBuffer/addAll_A01_t02: fail
+LibTest/core/StringBuffer/addAll_A03_t01: fail
+LibTest/core/StringBuffer/add_A01_t01: fail
+LibTest/core/StringBuffer/add_A01_t02: fail
+LibTest/core/StringBuffer/isEmpty_A01_t01: fail
+LibTest/core/StringBuffer/toString_A01_t01: fail
LibTest/core/double/ceil_A01_t05: fail
LibTest/core/double/floor_A01_t05: fail
+LibTest/core/int/operator_division_A01_t01: fail
+
+# fails locally, passes on bot
+Language/13_Libraries_and_Scripts/3_Parts_A02_t03: skip
# co19 issue #412, using 'null' as operand
-Language/11_Expressions/01_Constants_A11_t01: fail
-Language/11_Expressions/01_Constants_A12_t01: fail
-Language/11_Expressions/01_Constants_A13_t06: fail
+Language/11_Expressions/01_Constants_A11_t01: fail, OK
+Language/11_Expressions/01_Constants_A12_t01: fail, OK
+Language/11_Expressions/01_Constants_A13_t06: fail, OK
+
+# co19 issue #414, extra @compile-error
+Language/03_Overview/1_Scoping_A02_t28: fail, OK
+
+# co19 issue #416, function name is declared the parameter scope
+Language/03_Overview/1_Scoping_A02_t07: fail, OK
+Language/12_Statements/04_Local_Function_Declaration_A01_t01: fail, OK
+
+# co19 issue $417, 'if', 'while' and 'do-while' don't create scope
+Language/03_Overview/1_Scoping_A02_t11: fail, OK
+Language/03_Overview/1_Scoping_A02_t12: fail, OK
+Language/03_Overview/1_Scoping_A02_t16: fail, OK
+
[ $runtime == drt && $compiler == none ]
diff --git a/tests/co19/co19-dart2js.status b/tests/co19/co19-dart2js.status
index 861ba7a..ecc143f 100644
--- a/tests/co19/co19-dart2js.status
+++ b/tests/co19/co19-dart2js.status
@@ -230,10 +230,6 @@
[ $compiler == dart2js && $checked ]
Language/07_Classes/6_Constructors/1_Generative_Constructors_A17_t03: Fail # TODO(ahe): Please triage this failure.
Language/07_Classes/6_Constructors/1_Generative_Constructors_A17_t04: Fail # TODO(ahe): Please triage this failure.
-Language/07_Classes/6_Constructors/2_Factories_A06_t01: Fail # TODO(ahe): Please triage this failure.
-Language/07_Classes/6_Constructors/2_Factories_A06_t02: Fail # TODO(ahe): Please triage this failure.
-Language/07_Classes/6_Constructors/2_Factories_A06_t03: Fail # TODO(ahe): Please triage this failure.
-Language/07_Classes/6_Constructors/2_Factories_A06_t04: Fail # TODO(ahe): Please triage this failure.
Language/09_Generics/09_Generics_A03_t01: Fail # TODO(ahe): Please triage this failure.
Language/09_Generics/09_Generics_A04_t06: Fail # TODO(ahe): Please triage this failure.
Language/11_Expressions/03_Numbers_A05_t02: Fail # TODO(ahe): Please triage this failure.
diff --git a/tests/compiler/dart2js/analyze_api_test.dart b/tests/compiler/dart2js/analyze_api_test.dart
index 93ae53c..1cc88e4 100644
--- a/tests/compiler/dart2js/analyze_api_test.dart
+++ b/tests/compiler/dart2js/analyze_api_test.dart
@@ -27,8 +27,13 @@
// TODO(johnniwinther): Support canonical URIs as keys and message kinds as
// values.
const Map<String,List<String>> WHITE_LIST = const {
- 'html_dart2js.dart': const ['Warning: Using "new Symbol"', // Issue 10565.
- 'Warning: unreachable code'], // Issue 10617.
+ 'html_dart2js.dart':
+ const ['Warning: Using "new Symbol"', // Issue 10565.
+ 'Warning: unreachable code', // Issue 10617.
+ // Issue 10688:
+ 'Warning: no property named',
+ "Warning: 'UnsupportedError' is not callable",
+ "Warning: no operator [] in class Iterable"],
};
class CollectingDiagnosticHandler extends FormattingDiagnosticHandler {
diff --git a/tests/compiler/dart2js/call_site_simple_type_inferer_test.dart b/tests/compiler/dart2js/call_site_simple_type_inferer_test.dart
index 28d2995..8ff09c7 100644
--- a/tests/compiler/dart2js/call_site_simple_type_inferer_test.dart
+++ b/tests/compiler/dart2js/call_site_simple_type_inferer_test.dart
@@ -222,7 +222,7 @@
int index = 0;
signature.forEachParameter((Element element) {
Expect.equals(expectedTypes[index++],
- inferrer.internal.typeOf[element]);
+ inferrer.internal.typeOf[element].simplify(inferrer.compiler));
});
Expect.equals(index, expectedTypes.length);
});
@@ -245,14 +245,14 @@
runTest(TEST_5, (inferrer) => [inferrer.numType]);
runTest(TEST_6, (inferrer) => [inferrer.numType]);
runTest(TEST_7a, (inferrer) => [subclassOfInterceptor(inferrer)]);
- runTest(TEST_7b, (inferrer) => [inferrer.dynamicType]);
+ runTest(TEST_7b, (inferrer) => [inferrer.dynamicType.nonNullable()]);
// In the following tests, we can't infer the right types because we
// have recursive calls with the same parameters. We should build a
// constraint system for those, to find the types.
runTest(TEST_8, (inferrer) => [inferrer.dynamicType,
subclassOfInterceptor(inferrer),
- inferrer.dynamicType]);
+ inferrer.dynamicType.nonNullable()]);
runTest(TEST_9, (inferrer) => [inferrer.dynamicType, inferrer.dynamicType]);
runTest(TEST_10, (inferrer) => [inferrer.dynamicType, inferrer.dynamicType]);
runTest(TEST_11, (inferrer) => [subclassOfInterceptor(inferrer),
diff --git a/tests/compiler/dart2js/call_site_type_inferer_static_test.dart b/tests/compiler/dart2js/call_site_type_inferer_static_test.dart
index 2081157..5a77227 100644
--- a/tests/compiler/dart2js/call_site_type_inferer_static_test.dart
+++ b/tests/compiler/dart2js/call_site_type_inferer_static_test.dart
@@ -84,8 +84,9 @@
HTypeList types = compiler.backend.optimisticParameterTypes(x, null);
if (expectedTypes != null) {
Expect.isFalse(types.allUnknown);
- Expect.listEquals(expectedTypes.map((f) => f(compiler)).toList(),
- types.types);
+ Expect.listEquals(
+ expectedTypes.map((f) => f(compiler)).toList(),
+ types.types.map((e) => e.simplify(compiler)).toList());
} else {
Expect.isTrue(types.allUnknown);
}
diff --git a/tests/compiler/dart2js/call_site_type_inferer_test.dart b/tests/compiler/dart2js/call_site_type_inferer_test.dart
index 4a04eff..bad589f 100644
--- a/tests/compiler/dart2js/call_site_type_inferer_test.dart
+++ b/tests/compiler/dart2js/call_site_type_inferer_test.dart
@@ -228,7 +228,8 @@
.toList();
Expect.isFalse(types.allUnknown);
Expect.equals(expectedTypes.length, types.types.length);
- Expect.listEquals(expectedTypes, types.types);
+ Expect.listEquals(expectedTypes,
+ types.types.map((t) => t.simplify(compiler)).toList());
} else {
Expect.isTrue(types.allUnknown);
}
diff --git a/tests/compiler/dart2js/cpa_inference_test.dart b/tests/compiler/dart2js/cpa_inference_test.dart
index 619f3bf..334d825 100644
--- a/tests/compiler/dart2js/cpa_inference_test.dart
+++ b/tests/compiler/dart2js/cpa_inference_test.dart
@@ -1255,8 +1255,9 @@
Expect.equals(convert(singleton(a).union(singleton(b)).union(nullSingleton)),
new TypeMask.subclass(a.rawType));
- Expect.equals(convert(singleton(b).union(singleton(d))),
- new TypeMask.nonNullSubtype(a.rawType));
+ Expect.equals(
+ convert(singleton(b).union(singleton(d))).simplify(result.compiler),
+ new TypeMask.nonNullSubtype(a.rawType));
}
testSelectors() {
@@ -1302,7 +1303,7 @@
Selector foo = new Selector.call(buildSourceString("foo"), null, 0);
Expect.equals(
- inferredType(foo),
+ inferredType(foo).simplify(result.compiler),
new TypeMask.nonNullSubclass(abc.rawType));
Expect.equals(
inferredType(new TypedSelector.subclass(x.rawType, foo)),
@@ -1314,7 +1315,8 @@
inferredType(new TypedSelector.subclass(z.rawType, foo)),
new TypeMask.nonNullExact(a.rawType));
Expect.equals(
- inferredType(new TypedSelector.subclass(xy.rawType, foo)),
+ inferredType(new TypedSelector.subclass(
+ xy.rawType, foo)).simplify(result.compiler),
new TypeMask.nonNullSubclass(bc.rawType));
Selector bar = new Selector.call(buildSourceString("bar"), null, 0);
diff --git a/tests/compiler/dart2js/field_type_inferer_test.dart b/tests/compiler/dart2js/field_type_inferer_test.dart
index 901b06e..59db184 100644
--- a/tests/compiler/dart2js/field_type_inferer_test.dart
+++ b/tests/compiler/dart2js/field_type_inferer_test.dart
@@ -344,7 +344,8 @@
name,
disableInlining,
(backend, field) {
- HType inferredType = backend.optimisticFieldType(field);
+ HType inferredType =
+ backend.optimisticFieldType(field).simplify(backend.compiler);
if (type is Function) type = type(backend.compiler);
Expect.equals(type, inferredType);
});
diff --git a/tests/compiler/dart2js/field_type_simple_inferer_test.dart b/tests/compiler/dart2js/field_type_simple_inferer_test.dart
index 5a2f27b..7422b80 100644
--- a/tests/compiler/dart2js/field_type_simple_inferer_test.dart
+++ b/tests/compiler/dart2js/field_type_simple_inferer_test.dart
@@ -450,7 +450,8 @@
disableInlining,
(inferrer, field) {
TypeMask type = f(inferrer);
- TypeMask inferredType = inferrer.internal.typeOf[field];
+ TypeMask inferredType =
+ inferrer.internal.typeOf[field].simplify(inferrer.compiler);
Expect.equals(type, inferredType, name);
});
});
@@ -478,11 +479,10 @@
// code at the declaration site of the fields does not matter.
runTest(TEST_5, {'f1': subclassOfInterceptor,
'f2': subclassOfInterceptor});
- // TODO(9415). These tests seem flaky.
- //runTest(TEST_6, {'f1': subclassOfInterceptor,
- // 'f2': subclassOfInterceptor});
- //runTest(TEST_7, {'f1': subclassOfInterceptor,
- // 'f2': subclassOfInterceptor});
+ runTest(TEST_6, {'f1': subclassOfInterceptor,
+ 'f2': subclassOfInterceptor});
+ runTest(TEST_7, {'f1': subclassOfInterceptor,
+ 'f2': subclassOfInterceptor});
runTest(TEST_8, {'f': (inferrer) => inferrer.stringType.nullable()});
runTest(TEST_9, {'f': (inferrer) => inferrer.stringType.nullable()});
diff --git a/tests/compiler/dart2js/generate_at_use_site_test.dart b/tests/compiler/dart2js/generate_at_use_site_test.dart
index d0955cb..8204f6a 100644
--- a/tests/compiler/dart2js/generate_at_use_site_test.dart
+++ b/tests/compiler/dart2js/generate_at_use_site_test.dart
@@ -22,8 +22,23 @@
}
""";
+const String BAR = r"""
+bar() {
+ var isLeaf = (bar() != null) && bar();
+ // Because we're using a local variable, the graph gets an empty
+ // block between the [isLeaf] phi and the next instruction that uses
+ // it. The optimizer must take that new block into account in order
+ // to have the phi be generate at use uste.
+ if (isLeaf) return null;
+ return true;
+}
+""";
+
main() {
// Make sure we don't introduce a new variable.
RegExp regexp = new RegExp("var $anyIdentifier =");
compileAndDoNotMatch(FIB, 'fib', regexp);
+
+ regexp = new RegExp("isLeaf");
+ compileAndDoNotMatch(BAR, 'bar', regexp);
}
diff --git a/tests/compiler/dart2js/mock_compiler.dart b/tests/compiler/dart2js/mock_compiler.dart
index 8e95867..9129573 100644
--- a/tests/compiler/dart2js/mock_compiler.dart
+++ b/tests/compiler/dart2js/mock_compiler.dart
@@ -173,6 +173,7 @@
class _WorkerBase {}''';
class MockCompiler extends Compiler {
+ api.DiagnosticHandler diagnosticHandler;
List<WarningMessage> warnings;
List<WarningMessage> errors;
final Map<String, SourceFile> sourceFiles;
@@ -256,6 +257,8 @@
void reportWarning(Node node, var message) {
if (message is! Message) message = message.message;
warnings.add(new WarningMessage(node, message));
+ reportDiagnostic(spanFromNode(node),
+ 'Warning: $message', api.Diagnostic.WARNING);
}
void reportError(Node node, var message) {
@@ -265,6 +268,8 @@
}
if (message is! Message) message = message.message;
errors.add(new WarningMessage(node, message));
+ reportDiagnostic(spanFromNode(node),
+ 'Error: $message', api.Diagnostic.ERROR);
}
void reportMessage(SourceSpan span, var message, api.Diagnostic kind) {
@@ -274,10 +279,17 @@
} else {
warnings.add(diagnostic);
}
+ reportDiagnostic(span, "$message", kind);
}
- void reportDiagnostic(SourceSpan span, String message, var kind) {
- print(message);
+ void reportDiagnostic(SourceSpan span, String message, api.Diagnostic kind) {
+ if (diagnosticHandler != null) {
+ if (span != null) {
+ diagnosticHandler(span.uri, span.begin, span.end, message, kind);
+ } else {
+ diagnosticHandler(null, null, null, message, kind);
+ }
+ }
}
bool get compilationFailed => !errors.isEmpty;
@@ -319,7 +331,7 @@
parseScript(String text, [LibraryElement library]) {
if (library == null) library = mainApp;
- parseUnit(text, this, library);
+ parseUnit(text, this, library, registerSource);
}
void scanBuiltinLibraries() {
diff --git a/tests/compiler/dart2js/parser_helper.dart b/tests/compiler/dart2js/parser_helper.dart
index ec96f0e..3ba38e9 100644
--- a/tests/compiler/dart2js/parser_helper.dart
+++ b/tests/compiler/dart2js/parser_helper.dart
@@ -78,10 +78,17 @@
: super('<string>', text);
}
+var sourceCounter = 0;
+
Link<Element> parseUnit(String text, Compiler compiler,
- LibraryElement library) {
+ LibraryElement library,
+ [void registerSource(Uri uri, String source)]) {
Token tokens = scan(text);
- Uri uri = new Uri.fromComponents(scheme: "source");
+ Uri uri =
+ new Uri.fromComponents(scheme: "source", path: '${++sourceCounter}');
+ if (registerSource != null) {
+ registerSource(uri, text);
+ }
var script = new Script(uri, new MockFile(text));
var unit = new CompilationUnitElementX(script, library);
int id = 0;
diff --git a/tests/compiler/dart2js/return_type_inferer_test.dart b/tests/compiler/dart2js/return_type_inferer_test.dart
index 7f50c98..30b854d 100644
--- a/tests/compiler/dart2js/return_type_inferer_test.dart
+++ b/tests/compiler/dart2js/return_type_inferer_test.dart
@@ -72,7 +72,7 @@
var backend = compiler.backend;
HType type =
backend.optimisticReturnTypesWithRecompilationOnTypeChange(null, x);
- Expect.equals(findExpectedType(compiler), type);
+ Expect.equals(findExpectedType(compiler), type.simplify(compiler));
});
}
diff --git a/tests/compiler/dart2js/simple_inferrer_and_or_test.dart b/tests/compiler/dart2js/simple_inferrer_and_or_test.dart
index 14ef2d3..40c01a5 100644
--- a/tests/compiler/dart2js/simple_inferrer_and_or_test.dart
+++ b/tests/compiler/dart2js/simple_inferrer_and_or_test.dart
@@ -62,7 +62,8 @@
checkReturn(String name, type) {
var element = findElement(compiler, name);
- Expect.equals(type, typesInferrer.internal.returnTypeOf[element]);
+ Expect.equals(type,
+ typesInferrer.internal.returnTypeOf[element].simplify(compiler));
}
var subclassOfInterceptor =
@@ -71,7 +72,7 @@
checkReturn('returnDyn1', subclassOfInterceptor);
checkReturn('returnDyn2', subclassOfInterceptor);
checkReturn('returnDyn3', subclassOfInterceptor);
- checkReturn('returnDyn4', typesInferrer.dynamicType);
- checkReturn('returnDyn5', typesInferrer.dynamicType);
- checkReturn('returnDyn6', typesInferrer.dynamicType);
+ checkReturn('returnDyn4', typesInferrer.dynamicType.nonNullable());
+ checkReturn('returnDyn5', typesInferrer.dynamicType.nonNullable());
+ checkReturn('returnDyn6', typesInferrer.dynamicType.nonNullable());
}
diff --git a/tests/compiler/dart2js/simple_inferrer_final_field3_test.dart b/tests/compiler/dart2js/simple_inferrer_final_field3_test.dart
index cf1b4aa..b43693e 100644
--- a/tests/compiler/dart2js/simple_inferrer_final_field3_test.dart
+++ b/tests/compiler/dart2js/simple_inferrer_final_field3_test.dart
@@ -31,7 +31,8 @@
checkFieldTypeInClass(String className, String fieldName, type) {
var cls = findElement(compiler, className);
var element = cls.lookupLocalMember(buildSourceString(fieldName));
- Expect.equals(type, typesInferrer.internal.typeOf[element]);
+ Expect.equals(type,
+ typesInferrer.internal.typeOf[element].simplify(compiler));
}
checkFieldTypeInClass('A', 'dynamicField',
diff --git a/tests/compiler/dart2js/simple_inferrer_final_field_test.dart b/tests/compiler/dart2js/simple_inferrer_final_field_test.dart
index 2e24c53..2e3cc4c 100644
--- a/tests/compiler/dart2js/simple_inferrer_final_field_test.dart
+++ b/tests/compiler/dart2js/simple_inferrer_final_field_test.dart
@@ -34,12 +34,14 @@
checkFieldTypeInClass(String className, String fieldName, type) {
var cls = findElement(compiler, className);
var element = cls.lookupLocalMember(buildSourceString(fieldName));
- Expect.equals(type, typesInferrer.internal.typeOf[element]);
+ Expect.equals(type,
+ typesInferrer.internal.typeOf[element].simplify(compiler));
}
checkFieldTypeInClass('A', 'intField', typesInferrer.intType);
checkFieldTypeInClass('A', 'giveUpField1',
findTypeMask(compiler, 'Interceptor', 'nonNullSubclass'));
- checkFieldTypeInClass('A', 'giveUpField2', typesInferrer.dynamicType);
+ checkFieldTypeInClass('A', 'giveUpField2',
+ typesInferrer.dynamicType.nonNullable());
checkFieldTypeInClass('A', 'fieldParameter', typesInferrer.intType);
}
diff --git a/tests/compiler/dart2js/simple_inferrer_no_such_method_test.dart b/tests/compiler/dart2js/simple_inferrer_no_such_method_test.dart
index 5297520..91fb20d 100644
--- a/tests/compiler/dart2js/simple_inferrer_no_such_method_test.dart
+++ b/tests/compiler/dart2js/simple_inferrer_no_such_method_test.dart
@@ -71,7 +71,7 @@
test8() => new C().bar();
test9() => (a ? new B() : new C()).bar();
-// Can hit A.noSuchMethod, D.noSuchMethod and Object.noSuchMethod.
+// Can hit A.noSuchMethod and D.noSuchMethod.
test10() => (a ? new B() : new D()).bar();
// Can hit D.noSuchMethod.
@@ -101,15 +101,18 @@
checkReturn(String name, type) {
var element = findElement(compiler, name);
- Expect.equals(type, typesInferrer.internal.returnTypeOf[element], name);
+ Expect.equals(
+ type,
+ typesInferrer.internal.returnTypeOf[element].simplify(compiler),
+ name);
}
checkReturn('test1', typesInferrer.intType);
checkReturn('test2', typesInferrer.dynamicType);
checkReturn('test3', typesInferrer.intType);
checkReturn('test4', typesInferrer.mapType);
- checkReturn('test5', typesInferrer.dynamicType);
- checkReturn('test6', typesInferrer.dynamicType);
+ checkReturn('test5', typesInferrer.dynamicType.nonNullable());
+ checkReturn('test6', typesInferrer.dynamicType.nonNullable());
compiler = compilerFor(TEST2, uri);
compiler.runCompiler(uri);
@@ -129,6 +132,6 @@
checkReturn('test7', typesInferrer.intType);
checkReturn('test8', typesInferrer.intType);
checkReturn('test9', typesInferrer.intType);
- checkReturn('test10', typesInferrer.numType.nullable());
+ checkReturn('test10', typesInferrer.numType);
checkReturn('test11', typesInferrer.doubleType);
}
diff --git a/tests/compiler/dart2js/simple_inferrer_postfix_prefix_test.dart b/tests/compiler/dart2js/simple_inferrer_postfix_prefix_test.dart
index a879e29..3c9aaa1 100644
--- a/tests/compiler/dart2js/simple_inferrer_postfix_prefix_test.dart
+++ b/tests/compiler/dart2js/simple_inferrer_postfix_prefix_test.dart
@@ -69,7 +69,8 @@
checkReturnInClass(String className, String methodName, type) {
var cls = findElement(compiler, className);
var element = cls.lookupLocalMember(buildSourceString(methodName));
- Expect.equals(type, typesInferrer.internal.returnTypeOf[element]);
+ Expect.equals(type,
+ typesInferrer.internal.returnTypeOf[element].simplify(compiler));
}
var subclassOfInterceptor =
diff --git a/tests/compiler/dart2js/simple_inferrer_relations_test.dart b/tests/compiler/dart2js/simple_inferrer_relations_test.dart
index 1488c10..4b3af4a 100644
--- a/tests/compiler/dart2js/simple_inferrer_relations_test.dart
+++ b/tests/compiler/dart2js/simple_inferrer_relations_test.dart
@@ -52,7 +52,7 @@
void main() {
String generated = compileAll(TEST);
- if (!generated.contains(r'if ($.$eq(c, d))')) {
+ if (generated.contains(r'=== true')) {
print(generated);
Expect.fail("missing elision of '=== true'");
}
diff --git a/tests/compiler/dart2js/simple_inferrer_test.dart b/tests/compiler/dart2js/simple_inferrer_test.dart
index 485896c..cc15222 100644
--- a/tests/compiler/dart2js/simple_inferrer_test.dart
+++ b/tests/compiler/dart2js/simple_inferrer_test.dart
@@ -236,6 +236,24 @@
return topLevelGetter() as Foo;
}
+testDeadCode() {
+ return 42;
+ return 'foo';
+}
+
+testLabeledIf(a) {
+ var c;
+ L1: if (a > 1) {
+ if (a == 2) {
+ break L1;
+ }
+ c = 42;
+ } else {
+ c = 38;
+ }
+ return c;
+}
+
testSwitch1() {
var a = null;
switch (topLevelGetter) {
@@ -266,8 +284,57 @@
return b;
}
+testContinue1() {
+ var a = 42;
+ var b;
+ while (true) {
+ b = a + 54;
+ if (b == 42) continue;
+ a = 'foo';
+ }
+ return b;
+}
+
+testBreak1() {
+ var a = 42;
+ var b;
+ while (true) {
+ b = a + 54;
+ if (b == 42) break;
+ b = 'foo';
+ }
+ return b;
+}
+
+testContinue2() {
+ var a = 42;
+ var b;
+ while (true) {
+ b = a + 54;
+ if (b == 42) {
+ b = 'foo';
+ continue;
+ }
+ }
+ return b;
+}
+
+testBreak2() {
+ var a = 42;
+ var b;
+ while (true) {
+ b = a + 54;
+ if (b == 42) {
+ a = 'foo';
+ break;
+ }
+ }
+ return b;
+}
+
get topLevelGetter => 42;
returnDynamic() => topLevelGetter(42);
+returnTopLevelGetter() => topLevelGetter;
class A {
factory A() = A.generative;
@@ -296,6 +363,7 @@
returnInt6() => super.myField += 4;
returnInt7() => ++super[0];
returnInt8() => super[0] += 54;
+ returnInt9() => super.myField;
}
main() {
@@ -337,9 +405,16 @@
returnAsString();
returnIntAsNum();
returnAsTypedef();
+ returnTopLevelGetter();
+ testDeadCode();
+ testLabeledIf();
testSwitch1();
testSwitch2();
testSwitch3();
+ testContinue1();
+ testBreak1();
+ testContinue2();
+ testBreak2();
new A() == null;
new A()..returnInt1()
..returnInt2()
@@ -355,7 +430,8 @@
..returnInt5()
..returnInt6()
..returnInt7()
- ..returnInt8();
+ ..returnInt8()
+ ..returnInt9();
}
""";
@@ -367,7 +443,10 @@
checkReturn(String name, type) {
var element = findElement(compiler, name);
- Expect.equals(type, typesInferrer.internal.returnTypeOf[element], name);
+ Expect.equals(
+ type,
+ typesInferrer.internal.returnTypeOf[element].simplify(compiler),
+ name);
}
var interceptorType =
findTypeMask(compiler, 'Interceptor', 'nonNullSubclass');
@@ -412,15 +491,23 @@
new TypeMask.subtype(compiler.stringClass.computeType(compiler)));
checkReturn('returnIntAsNum', typesInferrer.intType);
checkReturn('returnAsTypedef', typesInferrer.functionType.nullable());
- checkReturn('testSwitch1',
- typesInferrer.intType.union(typesInferrer.doubleType, compiler).nullable());
+ checkReturn('returnTopLevelGetter', typesInferrer.intType);
+ checkReturn('testDeadCode', typesInferrer.intType);
+ checkReturn('testLabeledIf', typesInferrer.intType.nullable());
+ checkReturn('testSwitch1', typesInferrer.intType
+ .union(typesInferrer.doubleType, compiler).nullable().simplify(compiler));
checkReturn('testSwitch2', typesInferrer.intType);
checkReturn('testSwitch3', interceptorType.nullable());
+ checkReturn('testContinue1', interceptorType.nullable());
+ checkReturn('testBreak1', interceptorType.nullable());
+ checkReturn('testContinue2', interceptorType.nullable());
+ checkReturn('testBreak2', typesInferrer.intType.nullable());
checkReturnInClass(String className, String methodName, type) {
var cls = findElement(compiler, className);
var element = cls.lookupLocalMember(buildSourceString(methodName));
- Expect.equals(type, typesInferrer.internal.returnTypeOf[element]);
+ Expect.equals(type,
+ typesInferrer.internal.returnTypeOf[element].simplify(compiler));
}
checkReturnInClass('A', 'returnInt1', typesInferrer.intType);
@@ -439,6 +526,7 @@
checkReturnInClass('B', 'returnInt6', typesInferrer.intType);
checkReturnInClass('B', 'returnInt7', typesInferrer.intType);
checkReturnInClass('B', 'returnInt8', typesInferrer.intType);
+ checkReturnInClass('B', 'returnInt9', typesInferrer.intType);
checkFactoryConstructor(String className) {
var cls = findElement(compiler, className);
diff --git a/tests/compiler/dart2js/simple_inferrer_try_catch_test.dart b/tests/compiler/dart2js/simple_inferrer_try_catch_test.dart
index a080d4d..2b6ebef 100644
--- a/tests/compiler/dart2js/simple_inferrer_try_catch_test.dart
+++ b/tests/compiler/dart2js/simple_inferrer_try_catch_test.dart
@@ -161,7 +161,8 @@
checkReturn(String name, type) {
var element = findElement(compiler, name);
- Expect.equals(type, typesInferrer.internal.returnTypeOf[element]);
+ Expect.equals(type,
+ typesInferrer.internal.returnTypeOf[element].simplify(compiler));
}
checkReturn('returnInt1', typesInferrer.intType);
diff --git a/tests/compiler/dart2js/type_checker_test.dart b/tests/compiler/dart2js/type_checker_test.dart
index 1381be8..6b813b0 100644
--- a/tests/compiler/dart2js/type_checker_test.dart
+++ b/tests/compiler/dart2js/type_checker_test.dart
@@ -3,14 +3,16 @@
// BSD-style license that can be found in the LICENSE file.
import "package:expect/expect.dart";
+import '../../../sdk/lib/_internal/compiler/compiler.dart' as api;
import '../../../sdk/lib/_internal/compiler/implementation/elements/elements.dart';
import '../../../sdk/lib/_internal/compiler/implementation/tree/tree.dart';
import '../../../sdk/lib/_internal/compiler/implementation/util/util.dart';
+import '../../../sdk/lib/_internal/compiler/implementation/source_file.dart';
import 'mock_compiler.dart';
import 'parser_helper.dart';
import '../../../sdk/lib/_internal/compiler/implementation/elements/modelx.dart'
- show ElementX;
+ show ElementX, CompilationUnitElementX;
import '../../../sdk/lib/_internal/compiler/implementation/dart2jslib.dart'
hide SourceString;
@@ -38,7 +40,8 @@
// testNewExpression,
testConditionalExpression,
testIfStatement,
- testThis];
+ testThis,
+ testOperatorsAssignability];
for (Function test in tests) {
setup();
test();
@@ -111,19 +114,22 @@
analyze("{ var i = 1 ${op} 2; }");
analyze("{ var i = 1; i ${op}= 2; }");
analyze("{ int i; var j = (i = true) ${op} 2; }",
- MessageKind.NOT_ASSIGNABLE);
+ [MessageKind.NOT_ASSIGNABLE, MessageKind.OPERATOR_NOT_FOUND]);
analyze("{ int i; var j = 1 ${op} (i = true); }",
- MessageKind.NOT_ASSIGNABLE);
+ [MessageKind.NOT_ASSIGNABLE, MessageKind.NOT_ASSIGNABLE]);
}
for (final op in ['-', '~']) {
analyze("{ var i = ${op}1; }");
- analyze("{ int i; var j = ${op}(i = true); }", MessageKind.NOT_ASSIGNABLE);
+ analyze("{ int i; var j = ${op}(i = true); }",
+ [MessageKind.NOT_ASSIGNABLE, MessageKind.OPERATOR_NOT_FOUND]);
}
for (final op in ['++', '--']) {
analyze("{ int i = 1; int j = i${op}; }");
analyze("{ int i = 1; bool j = i${op}; }", MessageKind.NOT_ASSIGNABLE);
- analyze("{ bool b = true; bool j = b${op}; }");
- analyze("{ bool b = true; int j = ${op}b; }");
+ analyze("{ bool b = true; bool j = b${op}; }",
+ MessageKind.OPERATOR_NOT_FOUND);
+ analyze("{ bool b = true; int j = ${op}b; }",
+ MessageKind.OPERATOR_NOT_FOUND);
}
for (final op in ['||', '&&']) {
analyze("{ bool b = (true ${op} false); }");
@@ -131,13 +137,21 @@
analyze("{ bool b = (1 ${op} false); }", MessageKind.NOT_ASSIGNABLE);
analyze("{ bool b = (true ${op} 2); }", MessageKind.NOT_ASSIGNABLE);
}
- for (final op in ['>', '<', '<=', '>=', '==', '!=']) {
+ for (final op in ['>', '<', '<=', '>=']) {
analyze("{ bool b = 1 ${op} 2; }");
analyze("{ int i = 1 ${op} 2; }", MessageKind.NOT_ASSIGNABLE);
analyze("{ int i; bool b = (i = true) ${op} 2; }",
- MessageKind.NOT_ASSIGNABLE);
+ [MessageKind.NOT_ASSIGNABLE, MessageKind.OPERATOR_NOT_FOUND]);
analyze("{ int i; bool b = 1 ${op} (i = true); }",
- MessageKind.NOT_ASSIGNABLE);
+ [MessageKind.NOT_ASSIGNABLE, MessageKind.NOT_ASSIGNABLE]);
+ }
+ for (final op in ['==', '!=']) {
+ analyze("{ bool b = 1 ${op} 2; }");
+ analyze("{ int i = 1 ${op} 2; }", MessageKind.NOT_ASSIGNABLE);
+ analyze("{ int i; bool b = (i = true) ${op} 2; }",
+ MessageKind.NOT_ASSIGNABLE);
+ analyze("{ int i; bool b = 1 ${op} (i = true); }",
+ MessageKind.NOT_ASSIGNABLE);
}
}
@@ -495,6 +509,281 @@
analyzeIn(foo, "{ Foo f = this; }");
}
+const String CLASSES_WITH_OPERATORS = '''
+class Operators {
+ Operators operator +(Operators other) => this;
+ Operators operator -(Operators other) => this;
+ Operators operator -() => this;
+ Operators operator *(Operators other) => this;
+ Operators operator /(Operators other) => this;
+ Operators operator %(Operators other) => this;
+ Operators operator ~/(Operators other) => this;
+
+ Operators operator &(Operators other) => this;
+ Operators operator |(Operators other) => this;
+ Operators operator ^(Operators other) => this;
+
+ Operators operator ~() => this;
+
+ Operators operator <(Operators other) => true;
+ Operators operator >(Operators other) => false;
+ Operators operator <=(Operators other) => this;
+ Operators operator >=(Operators other) => this;
+
+ Operators operator <<(Operators other) => this;
+ Operators operator >>(Operators other) => this;
+
+ bool operator ==(Operators other) => true;
+
+ Operators operator [](Operators key) => this;
+ void operator []=(Operators key, Operators value) {}
+}
+
+class MismatchA {
+ int operator+(MismatchA other) => 0;
+ MismatchA operator-(int other) => this;
+
+ MismatchA operator[](int key) => this;
+ void operator[]=(int key, MismatchA value) {}
+}
+
+class MismatchB {
+ MismatchB operator+(MismatchB other) => this;
+
+ MismatchB operator[](int key) => this;
+ void operator[]=(String key, MismatchB value) {}
+}
+
+class MismatchC {
+ MismatchC operator+(MismatchC other) => this;
+
+ MismatchC operator[](int key) => this;
+ void operator[]=(int key, String value) {}
+}
+''';
+
+testOperatorsAssignability() {
+ compiler.parseScript(CLASSES_WITH_OPERATORS);
+
+ // Tests against Operators.
+
+ String header = """{
+ bool z;
+ Operators a;
+ Operators b;
+ Operators c;
+ """;
+
+ check(String text, [expectedWarnings]) {
+ analyze('$header $text }', expectedWarnings);
+ }
+
+ // Positive tests on operators.
+
+ check('c = a + b;');
+ check('c = a - b;');
+ check('c = -a;');
+ check('c = a * b;');
+ check('c = a / b;');
+ check('c = a % b;');
+ check('c = a ~/ b;');
+
+ check('c = a & b;');
+ check('c = a | b;');
+ check('c = a ^ b;');
+
+ check('c = ~a;');
+
+ check('c = a < b;');
+ check('c = a > b;');
+ check('c = a <= b;');
+ check('c = a >= b;');
+
+ check('c = a << b;');
+ check('c = a >> b;');
+
+ check('c = a[b];');
+
+ check('a[b] = c;');
+ check('a[b] += c;');
+ check('a[b] -= c;');
+ check('a[b] *= c;');
+ check('a[b] /= c;');
+ check('a[b] %= c;');
+ check('a[b] ~/= c;');
+ check('a[b] <<= c;');
+ check('a[b] >>= c;');
+ check('a[b] &= c;');
+ check('a[b] |= c;');
+ check('a[b] ^= c;');
+
+ check('a += b;');
+ check('a -= b;');
+ check('a *= b;');
+ check('a /= b;');
+ check('a %= b;');
+ check('a ~/= b;');
+
+ check('a <<= b;');
+ check('a >>= b;');
+
+ check('a &= b;');
+ check('a |= b;');
+ check('a ^= b;');
+
+ // Negative tests on operators.
+
+ // For the sake of brevity we misuse the terminology in comments:
+ // 'e1 is not assignable to e2' should be read as
+ // 'the type of e1 is not assignable to the type of e2', and
+ // 'e1 is not assignable to operator o on e2' should be read as
+ // 'the type of e1 is not assignable to the argument type of operator o
+ // on e2'.
+
+ // `0` is not assignable to operator + on `a`.
+ check('c = a + 0;', MessageKind.NOT_ASSIGNABLE);
+ // `a + b` is not assignable to `z`.
+ check('z = a + b;', MessageKind.NOT_ASSIGNABLE);
+
+ // `-a` is not assignable to `z`.
+ check('z = -a;', MessageKind.NOT_ASSIGNABLE);
+
+ // `0` is not assignable to operator [] on `a`.
+ check('c = a[0];', MessageKind.NOT_ASSIGNABLE);
+ // `a[b]` is not assignable to `z`.
+ check('z = a[b];', MessageKind.NOT_ASSIGNABLE);
+
+ // `0` is not assignable to operator [] on `a`.
+ // Warning suppressed for `0` is not assignable to operator []= on `a`.
+ check('a[0] *= c;', MessageKind.NOT_ASSIGNABLE);
+ // `z` is not assignable to operator * on `a[0]`.
+ check('a[b] *= z;', MessageKind.NOT_ASSIGNABLE);
+
+ check('b = a++;', MessageKind.NOT_ASSIGNABLE);
+ check('b = ++a;', MessageKind.NOT_ASSIGNABLE);
+ check('b = a--;', MessageKind.NOT_ASSIGNABLE);
+ check('b = --a;', MessageKind.NOT_ASSIGNABLE);
+
+ check('c = a[b]++;', MessageKind.NOT_ASSIGNABLE);
+ check('c = ++a[b];', MessageKind.NOT_ASSIGNABLE);
+ check('c = a[b]--;', MessageKind.NOT_ASSIGNABLE);
+ check('c = --a[b];', MessageKind.NOT_ASSIGNABLE);
+
+ check('z = a == b;');
+ check('z = a != b;');
+
+ for (String o in ['&&', '||']) {
+ check('z = z $o z;');
+ check('z = a $o z;', MessageKind.NOT_ASSIGNABLE);
+ check('z = z $o b;', MessageKind.NOT_ASSIGNABLE);
+ check('z = a $o b;',
+ [MessageKind.NOT_ASSIGNABLE, MessageKind.NOT_ASSIGNABLE]);
+ check('a = a $o b;',
+ [MessageKind.NOT_ASSIGNABLE, MessageKind.NOT_ASSIGNABLE,
+ MessageKind.NOT_ASSIGNABLE]);
+ }
+
+ check('z = !z;');
+ check('z = !a;', MessageKind.NOT_ASSIGNABLE);
+ check('a = !z;', MessageKind.NOT_ASSIGNABLE);
+ check('a = !a;',
+ [MessageKind.NOT_ASSIGNABLE, MessageKind.NOT_ASSIGNABLE]);
+
+
+ // Tests against MismatchA.
+
+ header = """{
+ MismatchA a;
+ MismatchA b;
+ MismatchA c;
+ """;
+
+ // Tests against int operator +(MismatchA other) => 0;
+
+ // `a + b` is not assignable to `c`.
+ check('c = a + b;', MessageKind.NOT_ASSIGNABLE);
+ // `a + b` is not assignable to `a`.
+ check('a += b;', MessageKind.NOT_ASSIGNABLE);
+ // `a[0] + b` is not assignable to `a[0]`.
+ check('a[0] += b;', MessageKind.NOT_ASSIGNABLE);
+
+ // 1 is not applicable to operator +.
+ check('b = a++;', MessageKind.NOT_ASSIGNABLE);
+ // 1 is not applicable to operator +.
+ // `++a` of type int is not assignable to `b`.
+ check('b = ++a;',
+ [MessageKind.NOT_ASSIGNABLE, MessageKind.NOT_ASSIGNABLE]);
+
+ // 1 is not applicable to operator +.
+ check('b = a[0]++;', MessageKind.NOT_ASSIGNABLE);
+ // 1 is not applicable to operator +.
+ // `++a[0]` of type int is not assignable to `b`.
+ check('b = ++a[0];',
+ [MessageKind.NOT_ASSIGNABLE, MessageKind.NOT_ASSIGNABLE]);
+
+ // Tests against: MismatchA operator -(int other) => this;
+
+ // `a - b` is not assignable to `c`.
+ check('c = a + b;', MessageKind.NOT_ASSIGNABLE);
+ // `a - b` is not assignable to `a`.
+ check('a += b;', MessageKind.NOT_ASSIGNABLE);
+ // `a[0] - b` is not assignable to `a[0]`.
+ check('a[0] += b;', MessageKind.NOT_ASSIGNABLE);
+
+ check('b = a--;');
+ check('b = --a;');
+
+ check('b = a[0]--;');
+ check('b = --a[0];');
+
+ // Tests against MismatchB.
+
+ header = """{
+ MismatchB a;
+ MismatchB b;
+ MismatchB c;
+ """;
+
+ // Tests against:
+ // MismatchB operator [](int key) => this;
+ // void operator []=(String key, MismatchB value) {}
+
+ // `0` is not applicable to operator []= on `a`.
+ check('a[0] = b;', MessageKind.NOT_ASSIGNABLE);
+
+ // `0` is not applicable to operator []= on `a`.
+ check('a[0] += b;', MessageKind.NOT_ASSIGNABLE);
+ // `""` is not applicable to operator [] on `a`.
+ check('a[""] += b;', MessageKind.NOT_ASSIGNABLE);
+ // `c` is not applicable to operator [] on `a`.
+ // `c` is not applicable to operator []= on `a`.
+ check('a[c] += b;',
+ [MessageKind.NOT_ASSIGNABLE, MessageKind.NOT_ASSIGNABLE]);
+
+
+ // Tests against MismatchB.
+
+ header = """{
+ MismatchC a;
+ MismatchC b;
+ MismatchC c;
+ """;
+
+ // Tests against:
+ // MismatchC operator[](int key) => this;
+ // void operator[]=(int key, String value) {}
+
+ // `b` is not assignable to `a[0]`.
+ check('a[0] += b;', MessageKind.NOT_ASSIGNABLE);
+ // `0` is not applicable to operator + on `a[0]`.
+ check('a[0] += "";',
+ [MessageKind.NOT_ASSIGNABLE, MessageKind.NOT_ASSIGNABLE]);
+ // `true` is not applicable to operator + on `a[0]`.
+ // `true` is not assignable to `a[0]`.
+ check('a[0] += true;',
+ [MessageKind.NOT_ASSIGNABLE, MessageKind.NOT_ASSIGNABLE]);
+}
+
const CLASS_WITH_METHODS = '''
class ClassWithMethods {
untypedNoArgumentMethod() {}
@@ -531,8 +820,45 @@
Node parseExpression(String text) =>
parseBodyCode(text, (parser, token) => parser.parseExpression(token));
+const String NUM_SOURCE = '''
+abstract class num {
+ num operator +(num other);
+ num operator -(num other);
+ num operator *(num other);
+ num operator %(num other);
+ double operator /(num other);
+ int operator ~/(num other);
+ num operator -();
+ bool operator <(num other);
+ bool operator <=(num other);
+ bool operator >(num other);
+ bool operator >=(num other);
+}
+''';
+
+const String INT_SOURCE = '''
+abstract class int extends num {
+ int operator &(int other);
+ int operator |(int other);
+ int operator ^(int other);
+ int operator ~();
+ int operator <<(int shiftAmount);
+ int operator >>(int shiftAmount);
+ int operator -();
+}
+''';
+
void setup() {
- compiler = new MockCompiler();
+ RegExp classNum = new RegExp(r'abstract class num {}');
+ Expect.isTrue(DEFAULT_CORELIB.contains(classNum));
+ RegExp classInt = new RegExp(r'abstract class int extends num { }');
+ Expect.isTrue(DEFAULT_CORELIB.contains(classInt));
+
+ String CORE_SOURCE = DEFAULT_CORELIB
+ .replaceAll(classNum, NUM_SOURCE)
+ .replaceAll(classInt, INT_SOURCE);
+
+ compiler = new MockCompiler(coreSource: CORE_SOURCE);
types = compiler.types;
voidType = compiler.types.voidType;
intType = compiler.intClass.computeType(compiler);
@@ -570,23 +896,56 @@
}
}
+api.DiagnosticHandler createHandler(String text) {
+ return (uri, int begin, int end, String message, kind) {
+ SourceFile sourceFile;
+ if (uri == null) {
+ sourceFile = new SourceFile('analysis', text);
+ } else {
+ sourceFile = compiler.sourceFiles[uri.toString()];
+ }
+ if (sourceFile != null) {
+ print(sourceFile.getLocationMessage(message, begin, end, true, (x) => x));
+ } else {
+ print(message);
+ }
+ };
+}
+
analyze(String text, [expectedWarnings]) {
if (expectedWarnings == null) expectedWarnings = [];
if (expectedWarnings is !List) expectedWarnings = [expectedWarnings];
+ compiler.diagnosticHandler = createHandler(text);
+
Token tokens = scan(text);
NodeListener listener = new NodeListener(compiler, null);
Parser parser = new Parser(listener);
parser.parseStatement(tokens);
Node node = listener.popNode();
+ Element compilationUnit =
+ new CompilationUnitElementX(new Script(null, null), compiler.mainApp);
Element function = new ElementX(
- buildSourceString(''), ElementKind.FUNCTION, compiler.mainApp);
+ buildSourceString(''), ElementKind.FUNCTION, compilationUnit);
TreeElements elements = compiler.resolveNodeStatement(node, function);
TypeCheckerVisitor checker = new TypeCheckerVisitor(compiler, elements,
types);
compiler.clearWarnings();
checker.analyze(node);
compareWarningKinds(text, expectedWarnings, compiler.warnings);
+ compiler.diagnosticHandler = null;
+}
+
+void generateOutput(String text) {
+ for (WarningMessage message in compiler.warnings) {
+ var beginToken = message.node.getBeginToken();
+ var endToken = message.node.getEndToken();
+ int begin = beginToken.charOffset;
+ int end = endToken.charOffset + endToken.slowCharCount;
+ SourceFile sourceFile = new SourceFile('analysis', text);
+ print(sourceFile.getLocationMessage(message.message.toString(),
+ begin, end, true, (str) => str));
+ }
}
analyzeIn(ClassElement classElement, String text, [expectedWarnings]) {
@@ -603,7 +962,7 @@
TypeCheckerVisitor checker = new TypeCheckerVisitor(compiler, elements,
types);
compiler.clearWarnings();
- checker.currentClass = classElement;
checker.analyze(node);
+ generateOutput(text);
compareWarningKinds(text, expectedWarnings, compiler.warnings);
}
diff --git a/tests/compiler/dart2js/type_combination_test.dart b/tests/compiler/dart2js/type_combination_test.dart
index 8a23071..3fea40e 100644
--- a/tests/compiler/dart2js/type_combination_test.dart
+++ b/tests/compiler/dart2js/type_combination_test.dart
@@ -96,7 +96,8 @@
}
void testUnion(MockCompiler compiler) {
- RuleSet ruleSet = new RuleSet('union', (t1, t2) => t1.union(t2, compiler));
+ RuleSet ruleSet = new RuleSet('union',
+ (t1, t2) => t1.union(t2, compiler).simplify(compiler));
rule(type1, type2, result) => ruleSet.rule(type1, type2, result);
check(type1, type2, predicate) => ruleSet.check(type1, type2, predicate);
diff --git a/tests/compiler/dart2js_extra/factory_test.dart b/tests/compiler/dart2js_extra/factory_test.dart
deleted file mode 100644
index 0d3e59b..0000000
--- a/tests/compiler/dart2js_extra/factory_test.dart
+++ /dev/null
@@ -1,15 +0,0 @@
-// 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.
-
-import "package:expect/expect.dart";
-
-class A {
- factory A() {
- return 1;
- }
-}
-
-main() {
- Expect.equals(1, new A());
-}
diff --git a/tests/compiler/dart2js_extra/type_error_message_test.dart b/tests/compiler/dart2js_extra/type_error_message_test.dart
new file mode 100644
index 0000000..220550b
--- /dev/null
+++ b/tests/compiler/dart2js_extra/type_error_message_test.dart
@@ -0,0 +1,31 @@
+// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:expect/expect.dart';
+
+class C<T, S> {}
+
+bool inCheckedMode() {
+ try {
+ int i = 'hest';
+ } catch (e) {
+ return true;
+ }
+ return false;
+}
+
+main() {
+ if (inCheckedMode()) {
+ bool caught = false;
+ try {
+ C<String, String> x = new C<C<int, String>, String>();
+ } catch (e) {
+ String expected = 'C<C<int, String>, String>';
+ Expect.isTrue(e.toString().contains(expected),
+ 'Expected "$expected" in the message');
+ caught = true;
+ }
+ Expect.isTrue(caught);
+ }
+}
diff --git a/tests/compiler/dart2js_native/native_exception2_test.dart b/tests/compiler/dart2js_native/native_exception2_test.dart
new file mode 100644
index 0000000..6f26332
--- /dev/null
+++ b/tests/compiler/dart2js_native/native_exception2_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.
+
+// Similar to native_exception_test.dart but also defines a native
+// class. This exercises a different code path in emitter.dart.
+
+library native_exception2_test;
+
+import 'native_exception_test.dart' as other;
+
+class NativeClass native "NativeClass" {
+}
+
+makeNativeClass() native;
+
+setup() native """
+function NativeClass() {}
+makeNativeClass = function() { return new NativeClass; }
+""";
+
+main() {
+ setup();
+ other.main();
+}
diff --git a/tests/compiler/dart2js_native/native_exception_test.dart b/tests/compiler/dart2js_native/native_exception_test.dart
new file mode 100644
index 0000000..9b1d346
--- /dev/null
+++ b/tests/compiler/dart2js_native/native_exception_test.dart
@@ -0,0 +1,34 @@
+// 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 dart2js can handle unexpected exception types.
+
+library native_exception_test;
+
+import 'dart:_foreign_helper' show JS;
+
+import "package:expect/expect.dart";
+
+main() {
+ var previous;
+ check(e) {
+ print('$e');
+ Expect.equals(e, e);
+ Expect.notEquals(e, new Object());
+ Expect.notEquals(e, previous);
+ previous = e;
+ return '$e' != '[object Object]';
+ }
+ Expect.throws(() { JS('void', 'noGlobalVariableWithThisName'); }, check);
+ Expect.throws(() { JS('void', 'throw 3'); }, check);
+ Expect.throws(
+ () {
+ JS('bool', 'Object.prototype.hasOwnProperty.call(undefined, "foo")');
+ },
+ check);
+ Expect.throws(() { JS('void', 'throw new ReferenceError()'); }, check);
+ Expect.throws(() { JS('void', 'throw void 0'); }, check);
+ Expect.throws(() { JS('void', 'throw "a string"'); }, check);
+ Expect.throws(() { JS('void', 'throw null'); }, check);
+}
diff --git a/tests/corelib/string_trim2_test.dart b/tests/corelib/string_trim2_test.dart
new file mode 100644
index 0000000..0f0ccab
--- /dev/null
+++ b/tests/corelib/string_trim2_test.dart
@@ -0,0 +1,48 @@
+// 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";
+
+// TODO(floitsch): Test 0x85 when dart2js supports it.
+const WHITESPACE = const [
+ 9,
+ 10,
+ 11,
+ 12,
+ 13,
+ 0x20,
+ 0xA0,
+ 0x1680,
+ 0x180E,
+ 0x2000,
+ 0x2001,
+ 0x2002,
+ 0x2003,
+ 0x2004,
+ 0x2005,
+ 0x2006,
+ 0x2007,
+ 0x2008,
+ 0x2009,
+ 0x200A,
+ 0x202F,
+ 0x205F,
+ 0x3000,
+ 0x2028,
+ 0x2029,
+ 0xFEFF,
+];
+
+main() {
+ for (var ws in WHITESPACE) {
+ Expect.equals("", new String.fromCharCode(ws).trim());
+ }
+ Expect.equals("", new String.fromCharCodes(WHITESPACE).trim());
+ for (var ws in WHITESPACE) {
+ var c = new String.fromCharCode(ws);
+ Expect.equals("a", ("a" + c).trim());
+ Expect.equals("a", (c + "a").trim());
+ Expect.equals("a", (c + c + "a" + c + c).trim());
+ }
+}
diff --git a/tests/html/html.status b/tests/html/html.status
index 409328c..255b99c 100644
--- a/tests/html/html.status
+++ b/tests/html/html.status
@@ -4,7 +4,6 @@
window_open_test: Skip # http://dartbug.com/5151
async_window_test: Skip #TODO(gram): investigating
-svg_test: Skip #TODO(vsm): investigating
event_test: Skip # Issue 1996
custom_elements_test: Skip # Not yet implemented.
@@ -13,6 +12,7 @@
[ $compiler == none && ($runtime == drt || $runtime == dartium) ]
# postMessage in dartium always transfers the typed array buffer, never a view
postmessage_structured_test/typed_arrays: Fail
+custom_element_bindings_test: Fail # To investigate.
[ $compiler == none && $runtime == drt && $system == windows ]
worker_test/functional: Pass, Crash # Issue 9929.
@@ -28,9 +28,6 @@
[ $compiler == dart2js && ( $runtime == ie9 || $runtime == ie10 ) ]
worker_api_test: Fail # IE does not support URL.createObjectURL in web workers.
-[ $compiler == dart2js && ( $runtime == ff ) ]
-worker_api_test: Fail # Requires Firefox 21.
-
[ $compiler == dart2js && $runtime == safari ]
url_test: Fail # Issue 10096
@@ -187,7 +184,6 @@
rtc_test/supported: Fail
shadow_dom_test/supported: Fail
speechrecognition_test/supported: Fail
-svg_test/supported_externalResourcesRequired: Fail
svgelement_test/supported_altGlyph: Fail
svgelement_test/supported_animate: Fail
svgelement_test/supported_animateMotion: Fail
@@ -265,6 +261,9 @@
speechrecognition_test/supported: Fail
touchevent_test/supported: Fail
+[ $runtime == ie9 && $checked ]
+element_types_test/constructors: Fail # Issue 10796
+
[ $runtime == opera ]
blob_constructor_test: Fail
canvas_test: Fail
@@ -306,8 +305,6 @@
notifications_test/supported: Fail
performance_api_test/supported: Fail
speechrecognition_test/supported: Fail
-svg_test/supported_externalResourcesRequired: Fail
-svg_test/supported_langSpace: Fail
websql_test/supported: Fail
[ $runtime == ff ]
@@ -320,7 +317,6 @@
# All changes should be accompanied by platform support annotation changes.
audiobuffersourcenode_test/supported: Fail
audiocontext_test/supported: Fail
-crypto_test/supported: Fail
css_test/supportsPointConversions: Fail
document_test/supports_cssCanvasContext: Fail
element_types_test/supported_content: Fail
@@ -346,8 +342,6 @@
rtc_test/supported: Fail # Release build does not enable by default.
shadow_dom_test/supported: Fail
speechrecognition_test/supported: Fail
-svg_test/supported_externalResourcesRequired: Fail
-svg_test/supported_langSpace: Fail
touchevent_test/supported: Fail
websql_test/supported: Fail
xhr_test/supported_HttpRequestProgressEvent: Fail
diff --git a/tests/html/svg_test.dart b/tests/html/svg_test.dart
index 156f379..db31807 100644
--- a/tests/html/svg_test.dart
+++ b/tests/html/svg_test.dart
@@ -68,15 +68,6 @@
var isSvgSvgElement =
predicate((x) => x is svg.SvgSvgElement, 'is a SvgSvgElement');
var isNode = predicate((x) => x is Node, 'is a Node');
- var isSvgTests = predicate((x) => x is svg.Tests, 'is a svg.Tests');
- var isSvgLangSpace = predicate((x) => x is svg.LangSpace, 'is a svg.LangSpace');
- var isSvgExternalResourcesRequired =
- predicate((x) => x is svg.ExternalResourcesRequired,
- 'is a svg.ExternalResourcesRequired');
- var isSvgTransformable =
- predicate((x) => x is svg.Transformable, 'is a svg.Transformable');
- var isSvgLocatable =
- predicate((x) => x is svg.Locatable, 'is a svg.Locatable');
var isSvgNumber = predicate((x) => x is svg.Number, 'is a svg.Number');
var isSvgRect = predicate((x) => x is svg.Rect, 'is a svg.Rect');
@@ -89,13 +80,6 @@
expect(r, isElement);
expect(r, isNode);
- // Other implemented interfaces.
- expect(r, isSvgTests);
- expect(r, isSvgLangSpace);
- expect(r, isSvgExternalResourcesRequired);
- expect(r, isSvgTransformable);
- expect(r, isSvgLocatable);
-
// Interfaces not implemented.
expect(r, isNot(isSvgNumber));
expect(r, isNot(isSvgRect));
@@ -116,24 +100,6 @@
return element;
}
- group('supported_externalResourcesRequired', () {
- test('supported', () {
- var div = insertTestDiv();
- var r = document.query('#rect1');
- expect(svg.ExternalResourcesRequired.supported(r), true);
- div.remove();
- });
- });
-
- group('supported_langSpace', () {
- test('supported', () {
- var div = insertTestDiv();
- var r = document.query('#rect1');
- expect(svg.LangSpace.supported(r), true);
- div.remove();
- });
- });
-
group('svgBehavioral', () {
// Test that SVG elements have the operations advertised through all the IDL
@@ -154,47 +120,6 @@
var isCssStyleDeclaration =
predicate((x) => x is CssStyleDeclaration, 'is a CssStyleDeclaration');
- /// Verifies that [e] supports the operations on the svg.Tests interface.
- checkSvgTests(e) {
- // Just check that the operations seem to exist.
- var rx = e.requiredExtensions;
- expect(rx, isStringList);
- var rf = e.requiredFeatures;
- expect(rf, isStringList);
- var sl = e.systemLanguage;
- expect(sl, isStringList);
-
- bool hasDoDo = e.hasExtension("DoDo");
- expect(hasDoDo, isFalse);
- }
-
- /// Verifies that [e] supports the operations on the svg.Locatable interface.
- checkSvgLocatable(e) {
- var v1 = e.farthestViewportElement;
- var v2 = e.nearestViewportElement;
- expect(v1, same(v2));
-
- var bbox = e.getBBox();
- expect(bbox, isSvgRect);
-
- var ctm = e.getCtm();
- expect(ctm, isSvgMatrix);
-
- var sctm = e.getScreenCtm();
- expect(sctm, isSvgMatrix);
-
- var xf2e = e.getTransformToElement(e);
- expect(xf2e, isSvgMatrix);
- }
-
- /**
- * Verifies that [e] supports the operations on the svg.Transformable
- * interface.
- */
- checkSvgTransformable(e) {
- var trans = e.transform;
- expect(trans, isSvgAnimatedTransformList);
- }
testRect(name, checker) {
test(name, () {
@@ -204,43 +129,6 @@
div.remove();
});
}
-
- /**
- * Verifies that [e] supports the operations on the svg.LangSpace interface.
- */
- checkSvgLangSpace(e) {
- if (svg.LangSpace.supported(e)) {
- // Just check that the attributes seem to exist.
- var lang = e.xmllang;
- e.xmllang = lang;
-
- String space = e.xmlspace;
- e.xmlspace = space;
-
- expect(lang, isString);
- expect(space, isString);
- }
- }
-
- /**
- * Verifies that [e] supports the operations on the
- * svg.ExternalResourcesRequired interface.
- */
- checkSvgExternalResourcesRequired(e) {
- if (svg.ExternalResourcesRequired.supported(e)) {
- var b = e.externalResourcesRequired;
- expect(b, isSvgAnimatedBoolean);
- expect(b.baseVal, isFalse);
- expect(b.animVal, isFalse);
- }
- }
-
- testRect('rect_SvgTests', checkSvgTests);
- testRect('rect_SvgLangSpace', checkSvgLangSpace);
- testRect('rect_SvgExternalResourcesRequired',
- checkSvgExternalResourcesRequired);
- testRect('rect_SvgLocatable', checkSvgLocatable);
- testRect('rect_SvgTransformable', checkSvgTransformable);
});
}
diff --git a/tests/isolate/isolate.status b/tests/isolate/isolate.status
index 8b8934f..6368aad 100644
--- a/tests/isolate/isolate.status
+++ b/tests/isolate/isolate.status
@@ -40,7 +40,6 @@
[ $compiler == dartanalyzer ]
isolate2_negative_test: fail
-isolate3_negative_test: fail
isolate_import_negative_test: fail
isolate_negative_test: fail
spawn_function_negative_test: fail
diff --git a/tests/language/factory_return_type_checked_test.dart b/tests/language/factory_return_type_checked_test.dart
new file mode 100644
index 0000000..dc46145
--- /dev/null
+++ b/tests/language/factory_return_type_checked_test.dart
@@ -0,0 +1,23 @@
+// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import "package:expect/expect.dart";
+
+class A {
+ factory A() => 42;
+}
+
+main() {
+ bool isCheckedMode = false;
+ try {
+ String a = 42;
+ } catch (e) {
+ isCheckedMode = true;
+ }
+ if (isCheckedMode) {
+ Expect.throws(() => new A(), (e) => e is TypeError);
+ } else {
+ Expect.equals(42, new A());
+ }
+}
diff --git a/tests/language/generic_list_checked_test.dart b/tests/language/generic_list_checked_test.dart
new file mode 100644
index 0000000..fcff24b
--- /dev/null
+++ b/tests/language/generic_list_checked_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.
+
+import 'package:expect/expect.dart';
+
+bool inCheckedMode() {
+ try {
+ int i = 'hest';
+ } catch (e) {
+ return true;
+ }
+ return false;
+}
+
+main() {
+ if (inCheckedMode()) {
+ Expect.throws(() { List<int> t = new List<String>(); });
+ }
+}
diff --git a/tests/language/inferrer_constructor_test.dart b/tests/language/inferrer_constructor_test.dart
new file mode 100644
index 0000000..38b97da
--- /dev/null
+++ b/tests/language/inferrer_constructor_test.dart
@@ -0,0 +1,24 @@
+// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// Test that dart2js type inferrer detects dead code.
+
+import "package:expect/expect.dart";
+
+class A {
+ var field;
+ A(test) {
+ if (test) {
+ return;
+ field = 42;
+ } else {
+ field = 54;
+ }
+ }
+}
+
+main() {
+ var a = new A(true);
+ Expect.throws(() => a.field + 42, (e) => e is NoSuchMethodError);
+}
diff --git a/tests/language/issue10561_test.dart b/tests/language/issue10561_test.dart
new file mode 100644
index 0000000..d02e157
--- /dev/null
+++ b/tests/language/issue10561_test.dart
@@ -0,0 +1,17 @@
+// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// Regression test for dart2js that used to miscompile classes
+// extending HashMap, because HashMap is patched.
+
+import "package:expect/expect.dart";
+
+import 'dart:collection';
+
+class Foo extends HashMap {
+}
+
+main() {
+ Expect.equals(0, new Foo().length);
+}
diff --git a/tests/language/issue10721_test.dart b/tests/language/issue10721_test.dart
new file mode 100644
index 0000000..4bad7a0
--- /dev/null
+++ b/tests/language/issue10721_test.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.
+
+import "package:expect/expect.dart";
+
+void main() {
+ Expect.equals('', useParameterInClosure(1));
+ Expect.equals(43, updateParameterInClosure(1)());
+}
+
+String useParameterInClosure(arg1, {int arg2}) {
+ if (arg1 is Map) {
+ return arg1.keys.map((key) => arg1[key]).first;
+ } else {
+ return '';
+ }
+}
+
+Function updateParameterInClosure(arg1) {
+ if (arg1 is Map) {
+ return () => arg1 = 42;
+ } else {
+ return () => arg1 = arg1 + 42;
+ }
+}
diff --git a/tests/language/issue10747_test.dart b/tests/language/issue10747_test.dart
new file mode 100644
index 0000000..fda6c49
--- /dev/null
+++ b/tests/language/issue10747_test.dart
@@ -0,0 +1,28 @@
+// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import "package:expect/expect.dart";
+
+class B<T> {
+}
+
+class A<T> {
+ var field;
+ A(this.field);
+ asTypeVariable() => field as T;
+ asBOfT() => field as B<T>;
+}
+
+main() {
+ Expect.equals(42, new A<int>(42).asTypeVariable());
+ Expect.throws(
+ () => new A<String>(42).asTypeVariable(),
+ (e) => e is CastError);
+
+ var b = new B<int>();
+ Expect.equals(b, new A<int>(b).asBOfT());
+ Expect.throws(
+ () => new A<String>(b).asBOfT(),
+ (e) => e is CastError);
+}
diff --git a/tests/language/issue10783_test.dart b/tests/language/issue10783_test.dart
new file mode 100644
index 0000000..c603f81
--- /dev/null
+++ b/tests/language/issue10783_test.dart
@@ -0,0 +1,17 @@
+// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import "package:expect/expect.dart";
+
+class C {
+ foo(int y) { return y; }
+}
+
+main() {
+ for (var b in [[false, 'pig']]) {
+ var c;
+ if (b[0]) c = new C();
+ Expect.throws(() => print(c.foo(b[1])), (e) => e is NoSuchMethodError);
+ }
+}
diff --git a/tests/language/language.status b/tests/language/language.status
index e7a5d61..a1fbeef 100644
--- a/tests/language/language.status
+++ b/tests/language/language.status
@@ -556,11 +556,6 @@
[ $compiler == dartanalyzer ]
abstract_factory_constructor_test/00: fail
assign_instance_method_negative_test: fail
-assign_static_type_test/01: fail
-assign_static_type_test/02: fail
-assign_static_type_test/03: fail
-assign_static_type_test/04: fail
-assign_static_type_test/05: fail
assign_static_type_test/06: fail
bad_named_parameters2_test: fail
bad_named_parameters_test: fail
@@ -576,21 +571,13 @@
call_constructor_on_unresolvable_class_test/02: fail
call_constructor_on_unresolvable_class_test/03: fail
call_constructor_on_unresolvable_class_test/07: fail
-call_non_method_field_test/01: fail
-call_non_method_field_test/02: fail
-call_nonexistent_static_test/01: fail
-call_nonexistent_static_test/02: fail
-call_nonexistent_static_test/03: fail
call_nonexistent_static_test/04: fail
-call_nonexistent_static_test/05: fail
call_nonexistent_static_test/06: fail
call_nonexistent_static_test/07: fail
-call_nonexistent_static_test/08: fail
call_nonexistent_static_test/09: fail
call_nonexistent_static_test/10: fail
call_through_getter_test: fail
-callable_test/00: fail
-callable_test/01: fail
+callable_test/none: fail
cast_test/04: fail
cast_test/05: fail
class_cycle_negative_test: fail
@@ -613,6 +600,7 @@
class_literal_test/27: fail
class_literal_test/28: fail
class_literal_test/29: fail
+class_literal_test/none: fail
closure_call_wrong_argument_count_negative_test: fail
compile_time_constant10_test/none: fail
compile_time_constant8_test: fail
@@ -623,6 +611,8 @@
compile_time_constant_arguments_test/05: fail
compile_time_constant_arguments_test/06: fail
compile_time_constant_b_test: fail
+compile_time_constant_c_test/01: fail
+compile_time_constant_c_test/02: fail
compile_time_constant_checked2_test/01: fail
compile_time_constant_checked2_test/02: fail
compile_time_constant_checked2_test/03: fail
@@ -635,11 +625,6 @@
compile_time_constant_checked3_test/04: fail
compile_time_constant_checked3_test/05: fail
compile_time_constant_checked3_test/06: fail
-compile_time_constant_checked_test/01: fail
-compile_time_constant_checked_test/02: fail
-compile_time_constant_checked_test/03: fail
-compile_time_constant_c_test/01: fail
-compile_time_constant_c_test/02: fail
compile_time_constant_d_test: fail
compile_time_constant_e_test: fail
compile_time_constant_test/02: fail
@@ -649,9 +634,6 @@
constructor3_negative_test: fail
constructor_call_wrong_argument_count_negative_test: fail
constructor_negative_test: fail
-constructor_redirect2_test/02: fail
-constructor_redirect2_test/04: fail
-constructor_redirect_test/01: fail
constructor_return_with_arrow_negative_test: fail
constructor_return_with_init_and_arrow_negative_test: fail
cyclic_type_variable_test/01: fail
@@ -660,33 +642,20 @@
cyclic_type_variable_test/04: fail
default_factory2_test/01: fail
default_implementation2_test: fail
-duplicate_constructor_test/01: fail
dynamic2_test/00: fail
dynamic_field_test: fail
export_cyclic_test: fail
f_bounded_quantification_test/01: fail
f_bounded_quantification_test/02: fail
-factory1_test/00: skip
-factory1_test/01: skip
factory2_test: fail
factory5_test/00: fail
-factory_implementation_test/00: skip
+factory_implementation_test/none: fail
factory_redirection2_test/01: fail
factory_redirection_test/07: fail
-factory_redirection_test/08: skip
-factory_redirection_test/09: skip
-factory_redirection_test/10: skip
-factory_redirection_test/11: skip
-factory_redirection_test/12: skip
-factory_redirection_test/13: skip
-factory_redirection_test/14: skip
fauxverride_test/03: fail
fauxverride_test/05: fail
field_method4_negative_test: fail
field_override_test/01: fail
-field_override_test/02: fail
-field_type_check_test/01: fail
-field_type_check2_test/01: skip
final_for_in_variable_test/01: fail
final_param_negative_test: fail
final_var_negative_test: fail
@@ -704,10 +673,7 @@
getter_no_setter_test/00: fail
getter_no_setter_test/01: fail
getters_setters2_test/01: fail
-getters_setters2_test/02: fail
-getters_setters2_test/03: skip
getters_setters_type_test/01: fail
-implicit_scope_test: fail
implicit_this_test/01: fail
implicit_this_test/04: fail
implicit_this_test/none: fail
@@ -725,14 +691,12 @@
interface_test/00: fail
internal_library_test/01: fail
is_not_class2_negative_test: fail
-issue1363_test: fail
library_juxtaposition_test: fail
licm_test: fail
list_literal1_negative_test: fail
list_literal_syntax_test/01: fail
list_literal_syntax_test/02: fail
list_literal_syntax_test/03: fail
-list_literal_syntax_test/05: fail
map_literal1_negative_test: fail
map_literal3_test: fail
method_override2_test/03: fail
@@ -754,11 +718,10 @@
named_parameters_aggregated_test/03: fail
named_parameters_aggregated_test/04: fail
named_parameters_aggregated_test/05: fail
-named_parameters_type_test: fail
-nested_switch_label_test: fail
new_expression_type_args_test/00: fail
new_expression_type_args_test/01: fail
new_expression_type_args_test/02: fail
+nested_switch_label_test: fail
no_such_method_negative_test: fail
non_const_super_negative_test: fail
number_identifier_negative_test: fail
@@ -771,8 +734,6 @@
override_field_test/03: fail
override_method_with_field_test/01: fail
override_method_with_field_test/02: fail
-parameter_initializer5_negative_test: fail
-positional_parameters_type_test: fail
prefix10_negative_test: fail
prefix11_negative_test: fail
prefix12_negative_test: fail
@@ -798,42 +759,12 @@
static_call_wrong_argument_count_negative_test: fail
static_field3_test/01: fail
static_field3_test/02: fail
-static_field3_test/03: fail
static_field3_test/04: fail
static_field_test/01: fail
static_field_test/02: fail
static_field_test/03: fail
-static_field_test/04: fail
static_final_field2_negative_test: fail
static_final_field_negative_test: fail
-string_interpolate1_negative_test: fail
-string_interpolate2_negative_test: fail
-string_interpolation2_negative_test: fail
-string_interpolation3_negative_test: fail
-string_interpolation4_negative_test: fail
-string_interpolation5_negative_test: fail
-string_interpolation6_negative_test: fail
-string_interpolation9_test/10: fail
-string_interpolation9_test/11: fail
-string_interpolation9_test/12: fail
-string_interpolation9_test/13: fail
-string_interpolation9_test/14: fail
-string_interpolation9_test/15: fail
-string_interpolation9_test/16: fail
-string_interpolation9_test/17: fail
-string_interpolation9_test/18: fail
-string_interpolation9_test/19: fail
-string_interpolation9_test/1: fail
-string_interpolation9_test/20: fail
-string_interpolation9_test/2: fail
-string_interpolation9_test/3: fail
-string_interpolation9_test/4: fail
-string_interpolation9_test/5: fail
-string_interpolation9_test/6: fail
-string_interpolation9_test/7: fail
-string_interpolation9_test/8: fail
-string_interpolation9_test/9: fail
-string_interpolation_test/01: fail
super_operator_index_test/01: fail
super_operator_index_test/02: fail
super_operator_index_test/03: fail
@@ -865,26 +796,16 @@
type_variable_bounds2_test/02: fail
type_variable_bounds2_test/03: fail
type_variable_bounds2_test/04: fail
-type_variable_bounds2_test/05: skip
type_variable_bounds2_test/06: fail
-type_variable_bounds3_test/00: skip
type_variable_bounds_test/00: fail
type_variable_bounds_test/01: fail
type_variable_bounds_test/02: fail
type_variable_bounds_test/03: fail
type_variable_bounds_test/04: fail
-type_variable_bounds_test/05: fail
type_variable_bounds_test/06: fail
type_variable_bounds_test/07: fail
type_variable_bounds_test/09: fail
-type_variable_bounds_test/10: fail
type_variable_identifier_expression_negative_test: fail
-type_variable_scope_test/00: skip
-type_variable_scope_test/01: skip
-type_variable_scope_test/02: skip
-type_variable_scope_test/03: skip
-type_variable_scope_test/04: skip
-type_variable_scope_test/05: skip
type_variable_static_context_negative_test: fail
typed_equality_test: fail
unary2_test: fail
@@ -892,15 +813,13 @@
unresolved_in_factory_negative_test: fail
unresolved_top_level_method_negative_test: fail
unresolved_top_level_var_negative_test: fail
-unsigned_right_shift_test/01: fail
-unsigned_right_shift_test/02: fail
-wrong_number_type_arguments_test/00: fail
-wrong_number_type_arguments_test/02: fail
# test issue 10683, It is a compile-time error if e refers to the name v or the name v=.
block_scope_test: fail
lazy_static3_test: fail
+# test issue 10752, there are 'implicit' scopes for 'if', 'while' and 'do-while'
+implicit_scope_test: fail, OK
[ $arch == arm ]
*: Skip
diff --git a/tests/language/language_dart2js.status b/tests/language/language_dart2js.status
index 1dfd21f..541b3c9 100644
--- a/tests/language/language_dart2js.status
+++ b/tests/language/language_dart2js.status
@@ -44,7 +44,6 @@
prefix16_test: Fail # dartbug.com/7354
default_factory2_test/01: Pass # For the wrong reasons.
type_variable_scope_test/none: Fail
-factory_implementation_test/00: Fail
redirecting_factory_infinite_steps_test/01: Fail
type_variable_bounds_test/01: Fail
type_variable_bounds_test/02: Fail
@@ -58,8 +57,6 @@
f_bounded_quantification_test/01: Fail
f_bounded_quantification_test/02: Fail
closure_type_test: Fail # does not detect type error in checked mode.
-factory1_test/00: Fail
-factory1_test/01: Fail
type_annotation_test/09: Fail # Named constructors interpreted as a type.
prefix15_test: Fail # Issue 5022
local_function2_test: Fail # Issue 5022
diff --git a/tests/lib/lib.status b/tests/lib/lib.status
index 26e406b..097a374 100644
--- a/tests/lib/lib.status
+++ b/tests/lib/lib.status
@@ -25,6 +25,9 @@
[ $compiler == dart2js && $checked ]
async/stream_event_transform_test: Fail # Issue 7733.
+[ $compiler == dart2js && $unchecked && ($runtime == d8 || $runtime == chrome || $runtime == drt) ]
+crypto/sha1_test: Fail # V8 bug: https://code.google.com/p/v8/issues/detail?id=2692
+
[ $compiler == dart2js && $jscl ]
async/future_test: Fail # Timer interface not supported; dartbug.com/7728.
async/slow_consumer2_test: Fail # Timer interface not supported; dartbug.com/7728.
diff --git a/tests/standalone/crypto/base64_test.dart b/tests/standalone/crypto/base64_test.dart
deleted file mode 100644
index 55546f0..0000000
--- a/tests/standalone/crypto/base64_test.dart
+++ /dev/null
@@ -1,71 +0,0 @@
-// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-import "package:expect/expect.dart";
-
-part "../../../sdk/lib/io/base64.dart";
-
-void main() {
- String line;
- String expected;
-
- line =
- "Man is distinguished, not only by his reason, but by this singular "
- "passion from other animals, which is a lust of the mind, that by a "
- "perseverance of delight in the continued and indefatigable generation "
- "of knowledge, exceeds the short vehemence of any carnal pleasure.";
- expected =
- "TWFuIGlzIGRpc3Rpbmd1aXNoZWQsIG5vdCBvbm"
- "x5IGJ5IGhpcyByZWFzb24sIGJ1dCBieSB0aGlz\r\n"
- "IHNpbmd1bGFyIHBhc3Npb24gZnJvbSBvdGhlci"
- "BhbmltYWxzLCB3aGljaCBpcyBhIGx1c3Qgb2Yg\r\n"
- "dGhlIG1pbmQsIHRoYXQgYnkgYSBwZXJzZXZlcm"
- "FuY2Ugb2YgZGVsaWdodCBpbiB0aGUgY29udGlu\r\n"
- "dWVkIGFuZCBpbmRlZmF0aWdhYmxlIGdlbmVyYX"
- "Rpb24gb2Yga25vd2xlZGdlLCBleGNlZWRzIHRo\r\n"
- "ZSBzaG9ydCB2ZWhlbWVuY2Ugb2YgYW55IGNhcm"
- "5hbCBwbGVhc3VyZS4=";
- Expect.equals(expected, _Base64._encode(line.codeUnits));
- Expect.listEquals(line.codeUnits, _Base64._decode(expected));
-
- line = "Simple string";
- expected = "U2ltcGxlIHN0cmluZw==";
- Expect.equals(expected, _Base64._encode(line.codeUnits));
- Expect.listEquals(line.codeUnits, _Base64._decode(expected));
-
- for (int i = 0; i < 256; i++) {
- List<int> x = [i];
- Expect.listEquals(x, _Base64._decode(_Base64._encode(x)));
- }
-
- for (int i = 0; i < 255; i++) {
- List<int> x = [i, i + 1];
- Expect.listEquals(x, _Base64._decode(_Base64._encode(x)));
- }
-
- for (int i = 0; i < 254; i++) {
- List<int> x = [i, i + 1, i + 2];
- Expect.listEquals(x, _Base64._decode(_Base64._encode(x)));
- }
-
- for (int i = 0; i < 253; i++) {
- List<int> x = [i, i + 1, i + 2, i + 3];
- Expect.listEquals(x, _Base64._decode(_Base64._encode(x)));
- }
-
- for (int i = 0; i < 252; i++) {
- List<int> x = [i, i + 1, i + 2, i + 3, i + 4];
- Expect.listEquals(x, _Base64._decode(_Base64._encode(x)));
- }
-
- for (int i = 0; i < 251; i++) {
- List<int> x = [i, i + 1, i + 2, i + 3, i + 4, i + 5];
- Expect.listEquals(x, _Base64._decode(_Base64._encode(x)));
- }
-
- for (int i = 0; i < 250; i++) {
- List<int> x = [i, i + 1, i + 2, i + 3, i + 4, i + 5, i + 6];
- Expect.listEquals(x, _Base64._decode(_Base64._encode(x)));
- }
-}
diff --git a/tests/standalone/io/file_input_stream_test.dart b/tests/standalone/io/file_input_stream_test.dart
index 93c9deb..d57c014 100644
--- a/tests/standalone/io/file_input_stream_test.dart
+++ b/tests/standalone/io/file_input_stream_test.dart
@@ -169,6 +169,61 @@
}
+void testInputStreamOffset() {
+ void test(int start, int end, int expectedBytes) {
+ var keepAlive = new ReceivePort();
+ var temp = new Directory('').createTempSync();
+ var file = new File('${temp.path}/input_stream_offset.txt');
+ var originalLength = writeLongFileSync(file);
+ var streamedBytes = 0;
+ if (expectedBytes < 0) expectedBytes = originalLength + expectedBytes;
+ file.openRead(start, end).listen(
+ (d) {
+ streamedBytes += d.length;
+ },
+ onDone: () {
+ Expect.equals(expectedBytes, streamedBytes);
+ temp.delete(recursive: true).then((_) => keepAlive.close());
+ },
+ onError: (e) {
+ Expect.fail("Unexpected error");
+ });
+ }
+ test(10, 20, 10);
+ test(10, 11, 1);
+ test(10, 10, 0);
+ test(100000000, null, 0);
+ test(null, 0, 0);
+ test(null, 1, 1);
+ test(1, null, -1);
+ test(20, null, -20);
+}
+
+
+void testInputStreamBadOffset() {
+ void test(int start, int end) {
+ var keepAlive = new ReceivePort();
+ var temp = new Directory('').createTempSync();
+ var file = new File('${temp.path}/input_stream_bad_offset.txt');
+ var originalLength = writeLongFileSync(file);
+ var streamedBytes = 0;
+ file.openRead(start, end).listen(
+ (d) {
+ streamedBytes += d.length;
+ },
+ onDone: () {
+ temp.delete(recursive: true);
+ },
+ onError: (e) {
+ keepAlive.close();
+ });
+ }
+ test(-1, null);
+ test(100, 99);
+ test(null, -1);
+}
+
+
void testStringLineTransformerEnding(String name, int length) {
String fileName = getFilename("tests/standalone/io/$name");
// File contains 10 lines.
@@ -198,6 +253,8 @@
testInputStreamTruncate();
testInputStreamDelete();
testInputStreamAppend();
+ testInputStreamOffset();
+ testInputStreamBadOffset();
// Check the length of these files as both are text files where one
// is without a terminating line separator which can easily be added
// back if accidentally opened in a text editor.
diff --git a/tests/standalone/io/http_client_timeout_test.dart b/tests/standalone/io/http_client_timeout_test.dart
new file mode 100644
index 0000000..0703abb4
--- /dev/null
+++ b/tests/standalone/io/http_client_timeout_test.dart
@@ -0,0 +1,85 @@
+// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:async';
+import 'dart:io';
+
+
+void testOneRequest(int connections) {
+ HttpServer.bind('127.0.0.1', 0).then((server) {
+ server.listen((request) => request.response.close());
+ var client = new HttpClient();
+ var futures = [];
+ for (int i = 0; i < connections; i++) {
+ futures.add(
+ client.get('127.0.0.1', server.port, '/')
+ .then((request) => request.close())
+ .then((response) => response.fold(null, (x, y) {})));
+ }
+ Future.wait(futures).then((_) {
+ new Timer.periodic(const Duration(milliseconds: 100), (timer) {
+ if (server.connectionsInfo().total == 0) {
+ timer.cancel();
+ server.close();
+ }
+ });
+ });
+ });
+}
+
+
+void testIdleTimeout(int timeout) {
+ HttpServer.bind('127.0.0.1', 0).then((server1) {
+ HttpServer.bind('127.0.0.1', 0).then((server2) {
+ server1.listen((request) => request.pipe(request.response));
+ server2.listen((request) => request.pipe(request.response));
+
+ var client = new HttpClient();
+ client.idleTimeout = new Duration(milliseconds: timeout);
+
+ // Create a 'slow' connection..
+ Future connect(int port) {
+ return client.post('127.0.0.1', port, '/')
+ .then((request) {
+ request.write("data");
+ new Timer(const Duration(milliseconds: 250), () {
+ request.close();
+ });
+ return request.done;
+ })
+ .then((response) {
+ return response.fold(null, (x, y) {});
+ });
+ }
+
+ // Create a single, slow request, to server1.
+ connect(server1.port);
+
+ // Create a repeating connection to server2.
+ run() {
+ connect(server2.port).then((_) {
+ if (server1.connectionsInfo().total == 0) {
+ server1.close();
+ server2.close();
+ return;
+ }
+ Timer.run(run);
+ });
+ }
+ run();
+ });
+ });
+}
+
+
+main() {
+ testOneRequest(1);
+ testOneRequest(5);
+ testOneRequest(20);
+ testIdleTimeout(0);
+ testIdleTimeout(100);
+ testIdleTimeout(500);
+ testIdleTimeout(1000);
+ testIdleTimeout(2000);
+}
diff --git a/tests/standalone/io/http_close_test.dart b/tests/standalone/io/http_close_test.dart
index a4f8175..17b4e47 100644
--- a/tests/standalone/io/http_close_test.dart
+++ b/tests/standalone/io/http_close_test.dart
@@ -111,9 +111,36 @@
}
+void testClientCloseWhileSendingRequest(int connections) {
+ HttpServer.bind("127.0.0.1", 0).then((server) {
+ int errors = 0;
+ server.listen((request) {
+ request.listen((_) {}, onError: (e) { errors++; });
+ });
+ var client = new HttpClient();
+ for (int i = 0; i < connections; i++) {
+ client.post("127.0.0.1", server.port, "/")
+ .then((request) {
+ request.contentLength = 110;
+ request.write("0123456789");
+ return request.close();
+ })
+ .catchError((_) {});
+ }
+ new Timer.periodic(const Duration(milliseconds: 100), (t) {
+ if (errors == connections && server.connectionsInfo().total == 0) {
+ t.cancel();
+ server.close();
+ }
+ });
+ });
+}
+
+
void main() {
testClientAndServerCloseNoListen(10);
testClientCloseServerListen(10);
testClientCloseSendingResponse(10);
+ testClientCloseWhileSendingRequest(10);
}
diff --git a/tests/standalone/io/process_echo_util.dart b/tests/standalone/io/process_echo_util.dart
new file mode 100644
index 0000000..1cc501d
--- /dev/null
+++ b/tests/standalone/io/process_echo_util.dart
@@ -0,0 +1,9 @@
+// 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:io";
+
+void main() {
+ new Options().arguments.forEach(print);
+}
diff --git a/tests/standalone/io/process_exit_negative_test.dart b/tests/standalone/io/process_exit_negative_test.dart
index 9eede27..418977f 100644
--- a/tests/standalone/io/process_exit_negative_test.dart
+++ b/tests/standalone/io/process_exit_negative_test.dart
@@ -9,14 +9,14 @@
import "process_test_util.dart";
void main() {
- Future<Process> fp = Process.start(getProcessTestFileName(),
- const ["0", "0", "0", "0"]);
+ var fp = Process.start(getProcessTestFileName(),
+ const ["0", "0", "0", "0"]);
fp.then((p) {
- p.onExit = (int s) {
+ p.exitCode.then((int s) {
print(a.toString()); // Should cause a compilation error here.
- };
+ });
// Drain stdout and stderr.
- p.stdout.onData = p.stdout.read;
- p.stderr.onData = p.stderr.read;
+ p.stdout.listen((_) {});
+ p.stderr.listen((_) {});
});
}
diff --git a/tests/standalone/io/process_shell_test.dart b/tests/standalone/io/process_shell_test.dart
new file mode 100644
index 0000000..add0c9f
--- /dev/null
+++ b/tests/standalone/io/process_shell_test.dart
@@ -0,0 +1,72 @@
+// 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:io";
+
+void testRunShell() {
+ test(args) {
+ var options = new Options();
+ var path = new Path(options.script);
+ path = path.directoryPath.join(new Path("process_echo_util.dart"));
+ Process.runShell(options.executable, [path.toString()]..addAll(args))
+ .then((result) {
+ if (Platform.operatingSystem == "windows") {
+ result = result.stdout.split("\r\n");
+ } else {
+ result = result.stdout.split("\n");
+ }
+ if (result.length - 1 != args.length) {
+ throw "wrong number of args: $args vs $result";
+ }
+ for (int i = 0; i < args.length; i++) {
+ if (args[i] != result[i]) {
+ throw "bad result at $i: '${args[i]}' vs '${result[i]}'";
+ }
+ }
+ });
+ }
+ test(["\""]);
+ test(["a b"]);
+ test(["'"]);
+ test(["'\"\"'\"'\"'"]);
+ test(["'\"\"'", "\"'\"'"]);
+ test(["'\$HOME'"]);
+ test(["'\$tmp'"]);
+}
+
+void testShell() {
+ test(args, expected) {
+ var options = new Options();
+ var path = new Path(options.script);
+ path = path.directoryPath.join(new Path("process_echo_util.dart"));
+ var command = "${options.executable} $path $args";
+ Process.runShell(command, [])
+ .then((result) {
+ if (Platform.operatingSystem == "windows") {
+ result = result.stdout.split("\r\n");
+ } else {
+ result = result.stdout.split("\n");
+ }
+ if (result.length - 1 != expected.length) {
+ throw "wrong number of args: $expected vs $result";
+ }
+ for (int i = 0; i < expected.length; i++) {
+ if (expected[i] != result[i]) {
+ throw "bad result at $i: ${expected[i]} vs ${result[i]}";
+ }
+ }
+ });
+ }
+ test("arg", ["arg"]);
+ test("arg1 arg2", ["arg1", "arg2"]);
+ if (Platform.operatingSystem != 'windows') {
+ test("arg1 arg2 > /dev/null", []);
+ }
+}
+
+void main() {
+ testRunShell();
+ testShell();
+}
+
diff --git a/tests/standalone/standalone.status b/tests/standalone/standalone.status
index 58dfb16..10e39ba 100644
--- a/tests/standalone/standalone.status
+++ b/tests/standalone/standalone.status
@@ -7,6 +7,9 @@
[ $runtime == vm && $system == macos ]
debugger/basic_debugger_test: Pass, Crash # Issue 10488.
+[ $runtime == vm && $system == windows ]
+debugger/*: Skip # Issue: 10791
+
[ $runtime == vm ]
# Fails because checked-in dart executable is not up to date.
io/test_runner_test: Fail
@@ -79,7 +82,6 @@
io/process_exit_negative_test: Fail # This is a compilation-time negative test.
[ $compiler == dartanalyzer ]
-crypto/base64_test: fail
io/file_constructor_test: fail
io/http_date_test: fail
io/http_headers_test: fail
diff --git a/tests/utils/dummy_compiler_test.dart b/tests/utils/dummy_compiler_test.dart
index 3ed3e17..ae44c27 100644
--- a/tests/utils/dummy_compiler_test.dart
+++ b/tests/utils/dummy_compiler_test.dart
@@ -52,8 +52,9 @@
var removeLast;
var add;
}
- class JSFixedArray {}
- class JSExtendableArray {}
+ class JSMutableArray {}
+ class JSFixedArray extends JSMutableArray {}
+ class JSExtendableArray extends JSMutableArray {}
class JSString {
var split;
var concat;
diff --git a/tools/VERSION b/tools/VERSION
index e85a212..004cbc5 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -1,4 +1,4 @@
MAJOR 0
MINOR 5
-BUILD 9
+BUILD 10
PATCH 0
diff --git a/tools/bots/compiler.py b/tools/bots/compiler.py
index 3cfd6e5..72cf2e6 100644
--- a/tools/bots/compiler.py
+++ b/tools/bots/compiler.py
@@ -219,9 +219,11 @@
# The dart2js compiler isn't self-hosted (yet) so we run its
# unit tests on the VM. We avoid doing this on the builders
# that run the browser tests to cut down on the cycle time.
+ unit_test_flags = [flag for flag in flags if flag.startswith('--shard')]
+ # Run the unit tests in checked mode (the VM's checked mode).
+ unit_test_flags.append('--checked')
TestStep("dart2js_unit", mode, system, 'none', 'vm', ['dart2js'],
- # Run the unit tests in checked mode (the VM's checked mode).
- ['--checked'])
+ unit_test_flags)
if system.startswith('win') and runtime.startswith('ie10'):
TestStep("dart2js", mode, system, 'dart2js', runtime, ['html'], flags)
diff --git a/tools/build.py b/tools/build.py
index 2426699..71b9247 100755
--- a/tools/build.py
+++ b/tools/build.py
@@ -108,7 +108,7 @@
# We have not yet tweaked the v8 dart build to work with the Android
# NDK/SDK, so don't try to build it.
if args == []:
- print "For android builds you must specify a target, such as 'dart'."
+ print "For android builds you must specify a target, such as 'samples'."
return False
if 'v8' in args:
print "The v8 target is not supported for android builds."
@@ -166,7 +166,7 @@
os.environ['ANDROID_TOOLCHAIN'] = android_toolchain
- android_sdk_version = 9
+ android_sdk_version = 15
android_sdk_tools = os.path.join(android_sdk_root, 'tools')
CheckDirExists(android_sdk_tools, 'Android SDK tools')
diff --git a/tools/dom/dom.json b/tools/dom/dom.json
index 22f3b28..cc9935d 100644
--- a/tools/dom/dom.json
+++ b/tools/dom/dom.json
@@ -3529,7 +3529,10 @@
"HTMLFormElement": {},
"acceptCharset": {},
"action": {},
- "autocomplete": {},
+ "autocomplete": {
+ "comment": "http://www.whatwg.org/specs/web-apps/current-work/multipage/association-of-controls-and-forms.html#autofilling-form-controls:-the-autocomplete-attribute",
+ "support_level": "experimental"
+ },
"checkValidity": {},
"elements": {},
"encoding": {},
@@ -5295,6 +5298,10 @@
},
"support_level": "untriaged"
},
+ "MIDIInput": {
+ "members": {},
+ "support_level": "untriaged"
+ },
"MIDIMessageEvent": {
"members": {
"data": {
@@ -5323,6 +5330,9 @@
"name": {
"support_level": "untriaged"
},
+ "ondisconnect": {
+ "support_level": "untriaged"
+ },
"removeEventListener": {
"support_level": "untriaged"
},
@@ -10173,12 +10183,27 @@
"lang": {
"support_level": "untriaged"
},
+ "onboundary": {
+ "support_level": "untriaged"
+ },
+ "onend": {
+ "support_level": "untriaged"
+ },
"onerror": {
"support_level": "untriaged"
},
+ "onmark": {
+ "support_level": "untriaged"
+ },
"onpause": {
"support_level": "untriaged"
},
+ "onresume": {
+ "support_level": "untriaged"
+ },
+ "onstart": {
+ "support_level": "untriaged"
+ },
"pitch": {
"support_level": "untriaged"
},
diff --git a/tools/dom/scripts/fremontcutbuilder.py b/tools/dom/scripts/fremontcutbuilder.py
index 3b172b2..16bf69a 100755
--- a/tools/dom/scripts/fremontcutbuilder.py
+++ b/tools/dom/scripts/fremontcutbuilder.py
@@ -12,40 +12,33 @@
_logger = logging.getLogger('fremontcutbuilder')
+# See:
+# http://src.chromium.org/viewvc/multivm/trunk/webkit/Source/core/features.gypi
+# for ENABLE_* flags defined in Chromium / Blink.
+# We list all ENABLE flags used in IDL in one of these two lists.
FEATURE_DISABLED = [
'ENABLE_BATTERY_STATUS',
- 'ENABLE_CSS3_CONDITIONAL_RULES',
'ENABLE_CSS_DEVICE_ADAPTATION',
'ENABLE_CUSTOM_SCHEME_HANDLER',
'ENABLE_ENCRYPTED_MEDIA_V2',
'ENABLE_MEDIA_CAPTURE', # Only enabled on Android.
'ENABLE_ORIENTATION_EVENTS', # Only enabled on Android.
- 'ENABLE_SPEECH_SYNTHESIS',
'ENABLE_WEBVTT_REGIONS',
'ENABLE_XHR_TIMEOUT',
]
FEATURE_DEFINES = [
- 'ENABLE_CALENDAR_PICKER',
- 'ENABLE_CANVAS_PROXY',
- 'ENABLE_CSS_REGIONS',
- 'ENABLE_CUSTOM_ELEMENTS',
- 'ENABLE_DATALIST_ELEMENT',
- 'ENABLE_DIALOG_ELEMENT',
+ 'ENABLE_CALENDAR_PICKER', # Not on Android
+ 'ENABLE_DATALIST_ELEMENT', # Not on Android
'ENABLE_ENCRYPTED_MEDIA',
- 'ENABLE_FONT_LOAD_EVENTS',
- 'ENABLE_GAMEPAD',
- 'ENABLE_INPUT_SPEECH',
- 'ENABLE_LEGACY_NOTIFICATIONS',
- 'ENABLE_MEDIA_STREAM',
- 'ENABLE_NAVIGATOR_CONTENT_UTILS',
- 'ENABLE_NOTIFICATIONS',
- 'ENABLE_PAGE_POPUP',
- 'ENABLE_SHARED_WORKERS',
+ 'ENABLE_INPUT_SPEECH', # Not on Android
+ 'ENABLE_LEGACY_NOTIFICATIONS', # Not on Android
+ 'ENABLE_NAVIGATOR_CONTENT_UTILS', # Not on Android
+ 'ENABLE_NOTIFICATIONS', # Not on Android
+ 'ENABLE_PAGE_POPUP', # Not on Android
'ENABLE_SVG',
'ENABLE_SVG_FONTS',
- 'ENABLE_VIDEO',
- 'ENABLE_WEB_AUDIO',
+ 'ENABLE_WEB_AUDIO', # Not on Android
'ENABLE_WEBGL',
]
@@ -111,11 +104,13 @@
if unused_conditionals:
_logger.warning('There are some unused conditionals %s' %
sorted(unused_conditionals))
+ _logger.warning('Please update fremontcutbuilder.py')
unknown_conditionals = conditionals_met - known_conditionals
if unknown_conditionals:
_logger.warning('There are some unknown conditionals %s' %
sorted(unknown_conditionals))
+ _logger.warning('Please update fremontcutbuilder.py')
db.Save()
return db
diff --git a/tools/dom/scripts/htmleventgenerator.py b/tools/dom/scripts/htmleventgenerator.py
index cdbade3..3ed4393 100644
--- a/tools/dom/scripts/htmleventgenerator.py
+++ b/tools/dom/scripts/htmleventgenerator.py
@@ -121,6 +121,7 @@
'DOMApplicationCache.progress': ('progress', 'Event'),
'DOMApplicationCache.updateready': ('updateReady', 'Event'),
'Document.readystatechange': ('readyStateChange', 'Event'),
+ 'Document.securitypolicyviolation': ('securityPolicyViolation', 'SecurityPolicyViolationEvent'),
'Document.selectionchange': ('selectionChange', 'Event'),
'Document.webkitpointerlockchange': ('pointerLockChange', 'Event'),
'Document.webkitpointerlockerror': ('pointerLockError', 'Event'),
@@ -135,8 +136,14 @@
'FileWriter.write': ('write', 'ProgressEvent'),
'FileWriter.writeend': ('writeEnd', 'ProgressEvent'),
'FileWriter.writestart': ('writeStart', 'ProgressEvent'),
+ 'FontLoader.load': ('load', 'CssFontFaceLoadEvent'),
+ 'FontLoader.loading': ('loading', 'CssFontFaceLoadEvent'),
+ 'FontLoader.loadingdone': ('loadingDone', 'CssFontFaceLoadEvent'),
+ 'FontLoader.loadstart': ('loadStart', 'CssFontFaceLoadEvent'),
'HTMLBodyElement.storage': ('storage', 'StorageEvent'),
'HTMLInputElement.webkitSpeechChange': ('speechChange', 'Event'),
+ 'HTMLFormElement.autocomplete': ('autocomplete', 'Event'),
+ 'HTMLFormElement.autocompleteerror': ('autocompleteError', 'AutocompleteErrorEvent'),
'HTMLMediaElement.loadstart': ('loadStart', 'Event'),
'HTMLMediaElement.progress': ('progress', 'Event'),
'HTMLMediaElement.show': ('show', 'Event'),
@@ -153,10 +160,12 @@
'MediaStream.removetrack': ('removeTrack', 'Event'),
'MediaStreamTrack.mute': ('mute', 'Event'),
'MediaStreamTrack.unmute': ('unmute', 'Event'),
+ 'MIDIPort.disconnect': ('disconnect', 'MidiConnectionEvent'),
'Notification.click': ('click', 'Event'),
'Notification.close': ('close', 'Event'),
'Notification.display': ('display', 'Event'),
'Notification.show': ('show', 'Event'),
+ 'Performance.webkitresourcetimingbufferfull': ('resourceTimingBufferFull', 'Event'),
'RTCDTMFSender.tonechange': ('toneChange', 'RtcDtmfToneChangeEvent'),
'RTCDataChannel.close': ('close', 'Event'),
'RTCDataChannel.open': ('open', 'Event'),
@@ -179,6 +188,11 @@
'SpeechRecognition.speechend': ('speechEnd', 'Event'),
'SpeechRecognition.speechstart': ('speechStart', 'Event'),
'SpeechRecognition.start': ('start', 'Event'),
+ 'SpeechSynthesisUtterance.boundary': ('boundary', 'SpeechSynthesisEvent'),
+ 'SpeechSynthesisUtterance.end': ('end', 'SpeechSynthesisEvent'),
+ 'SpeechSynthesisUtterance.mark': ('mark', 'SpeechSynthesisEvent'),
+ 'SpeechSynthesisUtterance.resume': ('resume', 'SpeechSynthesisEvent'),
+ 'SpeechSynthesisUtterance.start': ('start', 'SpeechSynthesisEvent'),
'TextTrack.cuechange': ('cueChange', 'Event'),
'TextTrackCue.enter': ('enter', 'Event'),
'TextTrackCue.exit': ('exit', 'Event'),
diff --git a/tools/dom/scripts/htmlrenamer.py b/tools/dom/scripts/htmlrenamer.py
index e28460c..7262ee1 100644
--- a/tools/dom/scripts/htmlrenamer.py
+++ b/tools/dom/scripts/htmlrenamer.py
@@ -56,7 +56,6 @@
'SVGSVGElement': 'SvgSvgElement', # Manual to avoid name conflicts.
'WebGLVertexArrayObjectOES': 'VertexArrayObject',
'XMLHttpRequest': 'HttpRequest',
- 'XMLHttpRequestException': 'HttpRequestException',
'XMLHttpRequestProgressEvent': 'HttpRequestProgressEvent',
'XMLHttpRequestUpload': 'HttpRequestUpload',
}, **typed_array_renames))
@@ -157,7 +156,6 @@
# browser.
_private_html_members = monitored.Set('htmlrenamer._private_html_members', [
'CanvasRenderingContext2D.arc',
- 'CanvasRenderingContext2D.drawImage',
'CompositionEvent.initCompositionEvent',
'CustomEvent.initCustomEvent',
'DeviceOrientationEvent.initDeviceOrientationEvent',
@@ -301,8 +299,6 @@
'UIEvent.layerY',
'UIEvent.pageX',
'UIEvent.pageY',
- 'WheelEvent.wheelDeltaX',
- 'WheelEvent.wheelDeltaY',
'WheelEvent.initWebKitWheelEvent',
'DOMWindow.getComputedStyle',
])
@@ -310,6 +306,7 @@
# Members from the standard dom that exist in the dart:html library with
# identical functionality but with cleaner names.
renamed_html_members = monitored.Dict('htmlrenamer.renamed_html_members', {
+ 'CanvasRenderingContext2D.drawImage': '_drawImage',
'CSSStyleDeclaration.getPropertyValue': '_getPropertyValue',
'CSSStyleDeclaration.setProperty': '_setProperty',
'DirectoryEntry.getDirectory': '_getDirectory',
@@ -346,6 +343,8 @@
'StorageInfo.queryUsageAndQuota': '_queryUsageAndQuota',
'SVGElement.className': '$dom_svgClassName',
'SVGStopElement.offset': 'gradientOffset',
+ 'WheelEvent.wheelDeltaX': '_wheelDeltaX',
+ 'WheelEvent.wheelDeltaY': '_wheelDeltaY',
#'WorkerContext.webkitRequestFileSystem': '_requestFileSystem',
#'WorkerContext.webkitRequestFileSystemSync': '_requestFileSystemSync',
})
diff --git a/tools/dom/scripts/idlparser.py b/tools/dom/scripts/idlparser.py
index 6583444..3142118 100755
--- a/tools/dom/scripts/idlparser.py
+++ b/tools/dom/scripts/idlparser.py
@@ -212,7 +212,7 @@
[MAYBE(ExtAttrs), MAYBE(Static), MAYBE(Stringifier), MAYBE(_Specials),
ReturnType, MAYBE(Id), '(', _Arguments, ')', ';'],
# WebKit:
- [MAYBE(ExtAttrs), MAYBE(Static), MAYBE(_AttrGetterSetter),
+ [MAYBE(ExtAttrs), MAYBE(Static), MAYBE(_Specials),
ReturnType, MAYBE(Id), '(', _Arguments, ')', ';'],
# FremontCut:
[MAYBE(_Annotations), MAYBE(ExtAttrs), MAYBE(Static), MAYBE(Stringifier),
diff --git a/tools/dom/scripts/logging.conf b/tools/dom/scripts/logging.conf
index 8645a8e..6dbf12e 100644
--- a/tools/dom/scripts/logging.conf
+++ b/tools/dom/scripts/logging.conf
@@ -1,5 +1,5 @@
[loggers]
-keys=root,pegparser,database,databasebuilder,dartgenerator,dartmetadata,snippet_manager,htmlrenamer
+keys=root,pegparser,database,databasebuilder,dartgenerator,dartmetadata,snippet_manager,htmlrenamer,fremontcutbuilder
[handlers]
keys=consoleHandler
@@ -29,6 +29,12 @@
handlers=consoleHandler
qualname=databasebuilder
+[logger_fremontcutbuilder]
+level=INFO
+propagate=0
+handlers=consoleHandler
+qualname=fremontcutbuilder
+
[logger_snippet_manager]
level=INFO
propagate=0
diff --git a/tools/dom/scripts/systemhtml.py b/tools/dom/scripts/systemhtml.py
index 0302a6c..c6463e1 100644
--- a/tools/dom/scripts/systemhtml.py
+++ b/tools/dom/scripts/systemhtml.py
@@ -708,8 +708,11 @@
#
ext_attrs = self._interface.ext_attrs
- has_indexed_getter = ('IndexedGetter' in ext_attrs or
- 'CustomIndexedSetter' in ext_attrs)
+ has_indexed_getter = 'CustomIndexedGetter' in ext_attrs
+ for operation in self._interface.operations:
+ if operation.id == 'item' and 'getter' in operation.specials:
+ has_indexed_getter = True
+ break
if has_indexed_getter:
indexed_getter = ('JS("%s", "#[#]", this, index)' %
diff --git a/tools/dom/scripts/systemnative.py b/tools/dom/scripts/systemnative.py
index a81e322..c5c8219 100644
--- a/tools/dom/scripts/systemnative.py
+++ b/tools/dom/scripts/systemnative.py
@@ -336,8 +336,7 @@
ext_attrs = self._interface.ext_attrs
- if ('CustomToJS' in ext_attrs or
- ('CustomToJSObject' in ext_attrs and 'TypedArray' not in ext_attrs) or
+ if ('CustomToV8' in ext_attrs or
'PureInterface' in ext_attrs or
'CPPPureInterface' in ext_attrs or
self._interface_type_info.custom_to_dart()):
diff --git a/tools/dom/src/EventStreamProvider.dart b/tools/dom/src/EventStreamProvider.dart
index 788b179..303a4e8 100644
--- a/tools/dom/src/EventStreamProvider.dart
+++ b/tools/dom/src/EventStreamProvider.dart
@@ -78,16 +78,16 @@
}
}
- bool get _paused => _pauseCount > 0;
+ bool get isPaused => _pauseCount > 0;
void resume() {
- if (_canceled || !_paused) return;
+ if (_canceled || !isPaused) return;
--_pauseCount;
_tryResume();
}
void _tryResume() {
- if (_onData != null && !_paused) {
+ if (_onData != null && !isPaused) {
_target.$dom_addEventListener(_eventType, _onData, _useCapture);
}
}
diff --git a/tools/dom/src/ImmutableListMixin.dart b/tools/dom/src/ImmutableListMixin.dart
index df14b40..2c05c11 100644
--- a/tools/dom/src/ImmutableListMixin.dart
+++ b/tools/dom/src/ImmutableListMixin.dart
@@ -47,7 +47,7 @@
throw new UnsupportedError("Cannot remove from immutable List.");
}
- void remove(Object object) {
+ bool remove(Object object) {
throw new UnsupportedError("Cannot remove from immutable List.");
}
@@ -59,7 +59,7 @@
throw new UnsupportedError("Cannot remove from immutable List.");
}
- void setRange(int start, int end, Iterable<E> iterable, [int skipCount]) {
+ void setRange(int start, int end, Iterable<E> iterable, [int skipCount = 0]) {
throw new UnsupportedError("Cannot setRange on immutable List.");
}
diff --git a/tools/dom/src/TemplateBindings.dart b/tools/dom/src/TemplateBindings.dart
index 9841aee..81cebd3 100644
--- a/tools/dom/src/TemplateBindings.dart
+++ b/tools/dom/src/TemplateBindings.dart
@@ -378,7 +378,7 @@
}
// http://dvcs.w3.org/hg/webcomponents/raw-file/tip/spec/templates/index.html#dfn-template-contents-owner
- static Document _getTemplateContentsOwner(Document doc) {
+ static Document _getTemplateContentsOwner(HtmlDocument doc) {
if (doc.window == null) {
return doc;
}
@@ -456,7 +456,7 @@
// template.
// TODO(jmesserly): node is DocumentFragment or Element
var descendents = (node as dynamic).queryAll(_allTemplatesSelectors);
- if (node is Element && node.isTemplate) bootstrap(node);
+ if (node is Element && (node as Element).isTemplate) bootstrap(node);
descendents.forEach(bootstrap);
}
@@ -610,7 +610,7 @@
static void _removeChild(Node parent, Node child) {
child._templateInstance = null;
- if (child is Element && child.isTemplate) {
+ if (child is Element && (child as Element).isTemplate) {
// Make sure we stop observing when we remove an element.
var templateIterator = child._templateIterator;
if (templateIterator != null) {
diff --git a/tools/dom/src/WrappedList.dart b/tools/dom/src/WrappedList.dart
index 3baff3e..b725b96 100644
--- a/tools/dom/src/WrappedList.dart
+++ b/tools/dom/src/WrappedList.dart
@@ -23,7 +23,7 @@
void add(E element) { _list.add(element); }
- void remove(Object element) { _list.remove(element); }
+ bool remove(Object element) => _list.remove(element);
void clear() { _list.clear(); }
diff --git a/tools/dom/src/dart2js_Conversions.dart b/tools/dom/src/dart2js_Conversions.dart
index 1c51b29..86f32fb 100644
--- a/tools/dom/src/dart2js_Conversions.dart
+++ b/tools/dom/src/dart2js_Conversions.dart
@@ -32,8 +32,14 @@
// Assume it's a Window if it contains the setInterval property. It may be
// from a different frame - without a patched prototype - so we cannot
// rely on Dart type checking.
- if (JS('bool', r'"setInterval" in #', e))
- return _DOMWindowCrossFrame._createSafe(e);
+ if (JS('bool', r'"setInterval" in #', e)) {
+ var window = _DOMWindowCrossFrame._createSafe(e);
+ // If it's a native window.
+ if (window is EventTarget) {
+ return window;
+ }
+ return null;
+ }
else
return e;
}
diff --git a/tools/dom/src/dartium_KeyEvent.dart b/tools/dom/src/dartium_KeyEvent.dart
index b627b9c..5be433b 100644
--- a/tools/dom/src/dartium_KeyEvent.dart
+++ b/tools/dom/src/dartium_KeyEvent.dart
@@ -66,6 +66,8 @@
/** True if the altGraphKey is pressed during this event. */
bool get altGraphKey => _parent.altGraphKey;
+ /** Accessor to the clipboardData available for this event. */
+ DataTransfer get clipboardData => _parent.clipboardData;
/** True if the ctrl key is pressed during this event. */
bool get ctrlKey => _parent.ctrlKey;
int get detail => _parent.detail;
diff --git a/tools/dom/templates/html/dart2js/html_dart2js.darttemplate b/tools/dom/templates/html/dart2js/html_dart2js.darttemplate
index 28e1d55..2a20d31 100644
--- a/tools/dom/templates/html/dart2js/html_dart2js.darttemplate
+++ b/tools/dom/templates/html/dart2js/html_dart2js.darttemplate
@@ -94,4 +94,4 @@
return JS('var', r'ReceivePortSync.dispatchCall(#, #)', id, message);
}
-spawnDomFunction(f) => IsolateNatives.spawnDomFunction(f);
+spawnDomFunction(Function f) => IsolateNatives.spawnDomFunction(f);
diff --git a/tools/dom/templates/html/dart2js/impl_Console.darttemplate b/tools/dom/templates/html/dart2js/impl_Console.darttemplate
index 25d08e1..84527d2 100644
--- a/tools/dom/templates/html/dart2js/impl_Console.darttemplate
+++ b/tools/dom/templates/html/dart2js/impl_Console.darttemplate
@@ -6,7 +6,7 @@
$(ANNOTATIONS)class Console {
- static Console safeConsole = new Console();
+ static Console _safeConsole = new Console();
bool get _isConsoleDefined => JS('bool', 'typeof console != "undefined"');
@@ -79,8 +79,8 @@
JS('void', 'console.time(#)', title) : null;
@DomName('Console.timeEnd')
- void timeEnd(String timerName) => _isConsoleDefined ?
- JS('void', 'console.timeEnd(#)', timerName) : null;
+ void timeEnd(String title) => _isConsoleDefined ?
+ JS('void', 'console.timeEnd(#)', title) : null;
@DomName('Console.timeStamp')
void timeStamp(Object arg) => _isConsoleDefined ?
diff --git a/tools/dom/templates/html/dart2js/impl_MouseEvent.darttemplate b/tools/dom/templates/html/dart2js/impl_MouseEvent.darttemplate
index 9792bf1..d4e304d 100644
--- a/tools/dom/templates/html/dart2js/impl_MouseEvent.darttemplate
+++ b/tools/dom/templates/html/dart2js/impl_MouseEvent.darttemplate
@@ -64,13 +64,12 @@
return new Point(x, y);
} else {
// Firefox does not support offsetX.
- var target = this.target;
- if (!(target is Element)) {
+ if (!(this.target is Element)) {
throw new UnsupportedError(
'offsetX is only supported on elements');
}
- return (this.client -
- this.target.getBoundingClientRect().topLeft).toInt();
+ Element target = this.target;
+ return (this.client - target.getBoundingClientRect().topLeft).toInt();
}
}
diff --git a/tools/dom/templates/html/dart2js/impl_URL.darttemplate b/tools/dom/templates/html/dart2js/impl_URL.darttemplate
index 30c4161..3da9a69 100644
--- a/tools/dom/templates/html/dart2js/impl_URL.darttemplate
+++ b/tools/dom/templates/html/dart2js/impl_URL.darttemplate
@@ -11,8 +11,8 @@
'(self.URL || self.webkitURL).createObjectURL(#)',
blob_OR_source_OR_stream);
- static void revokeObjectUrl(String objectUrl) =>
+ static void revokeObjectUrl(String url) =>
JS('void',
- '(self.URL || self.webkitURL).revokeObjectURL(#)', objectUrl);
+ '(self.URL || self.webkitURL).revokeObjectURL(#)', url);
$!MEMBERS
}
diff --git a/tools/dom/templates/html/impl/impl_CanvasRenderingContext2D.darttemplate b/tools/dom/templates/html/impl/impl_CanvasRenderingContext2D.darttemplate
index 1fca45d..22b56c2 100644
--- a/tools/dom/templates/html/impl/impl_CanvasRenderingContext2D.darttemplate
+++ b/tools/dom/templates/html/impl/impl_CanvasRenderingContext2D.darttemplate
@@ -112,13 +112,13 @@
}
$else
if (sourceRect == null) {
- $dom_drawImage(source,
+ _drawImage(source,
destRect.left,
destRect.top,
destRect.width,
destRect.height);
} else {
- $dom_drawImage(source,
+ _drawImage(source,
sourceRect.left,
sourceRect.top,
sourceRect.width,
@@ -166,7 +166,7 @@
void drawImage(CanvasImageSource source, num destX, num destY) native;
$else
void drawImage(CanvasImageSource source, num destX, num destY) {
- $dom_drawImage(source, destX, destY);
+ _drawImage(source, destX, destY);
}
$endif
@@ -204,7 +204,7 @@
$else
void drawImageScaled(CanvasImageSource source,
num destX, num destY, num destWidth, num destHeight) {
- $dom_drawImage(source, destX, destY, destWidth, destHeight);
+ _drawImage(source, destX, destY, destWidth, destHeight);
}
$endif
@@ -247,7 +247,7 @@
void drawImageScaledFromSource(CanvasImageSource source,
num sourceX, num sourceY, num sourceWidth, num sourceHeight,
num destX, num destY, num destWidth, num destHeight) {
- $dom_drawImage(source, sourceX, sourceY, sourceWidth, sourceHeight,
+ _drawImage(source, sourceX, sourceY, sourceWidth, sourceHeight,
destX, destY, destWidth, destHeight);
}
$endif
@@ -258,7 +258,7 @@
'#.lineDashOffset || #.webkitLineDashOffset', this, this);
@DomName('CanvasRenderingContext2D.lineDashOffset')
- void set lineDashOffset(num value) => JS('void',
+ void set lineDashOffset(num value) => JS('void',
'typeof #.lineDashOffset != "undefined" ? #.lineDashOffset = # : '
'#.webkitLineDashOffset = #', this, this, value, this, value);
$else
diff --git a/tools/dom/templates/html/impl/impl_Element.darttemplate b/tools/dom/templates/html/impl/impl_Element.darttemplate
index 261a6cd..188759e 100644
--- a/tools/dom/templates/html/impl/impl_Element.darttemplate
+++ b/tools/dom/templates/html/impl/impl_Element.darttemplate
@@ -564,11 +564,11 @@
* * [insertAdjacentText]
* * [insertAdjacentElement]
*/
- void insertAdjacentHtml(String where, String text) {
+ void insertAdjacentHtml(String where, String html) {
if (JS('bool', '!!#.insertAdjacentHtml', this)) {
- _insertAdjacentHtml(where, text);
+ _insertAdjacentHtml(where, html);
} else {
- _insertAdjacentNode(where, new DocumentFragment.html(text));
+ _insertAdjacentNode(where, new DocumentFragment.html(html));
}
}
@@ -636,7 +636,9 @@
$else
$endif
- @Creates('Null')
+$if DART2JS
+ @Creates('Null') // Set from Dart code; does not instantiate a native type.
+$endif
Map<String, StreamSubscription> _attributeBindings;
// TODO(jmesserly): I'm concerned about adding these to every element.
diff --git a/tools/dom/templates/html/impl/impl_Node.darttemplate b/tools/dom/templates/html/impl/impl_Node.darttemplate
index 04b03cd..287151f 100644
--- a/tools/dom/templates/html/impl/impl_Node.darttemplate
+++ b/tools/dom/templates/html/impl/impl_Node.darttemplate
@@ -57,11 +57,12 @@
void addAll(Iterable<Node> iterable) {
if (iterable is _ChildNodeListLazy) {
- if (!identical(iterable._this, _this)) {
+ _ChildNodeListLazy otherList = iterable;
+ if (!identical(otherList._this, _this)) {
// Optimized route for copying between nodes.
- for (var i = 0, len = iterable.length; i < len; ++i) {
+ for (var i = 0, len = otherList.length; i < len; ++i) {
// Should use $dom_firstChild, Bug 8886.
- _this.append(iterable[0]);
+ _this.append(otherList[0]);
}
}
return;
diff --git a/tools/dom/templates/html/impl/impl_SVGElement.darttemplate b/tools/dom/templates/html/impl/impl_SVGElement.darttemplate
index 8ac5997..d196fc1 100644
--- a/tools/dom/templates/html/impl/impl_SVGElement.darttemplate
+++ b/tools/dom/templates/html/impl/impl_SVGElement.darttemplate
@@ -44,7 +44,7 @@
return _cssClassSet;
}
- List<Element> get children => new FilteredElementList(this);
+ List<Element> get children => new FilteredElementList<Element>(this);
void set children(List<Element> value) {
final children = this.children;
diff --git a/tools/dom/templates/html/impl/impl_WheelEvent.darttemplate b/tools/dom/templates/html/impl/impl_WheelEvent.darttemplate
index 1e4b239..dcad713 100644
--- a/tools/dom/templates/html/impl/impl_WheelEvent.darttemplate
+++ b/tools/dom/templates/html/impl/impl_WheelEvent.darttemplate
@@ -230,7 +230,7 @@
* * [WheelEvent.deltaX](http://dev.w3.org/2006/webapi/DOM-Level-3-Events/html/DOM3-Events.html#events-WheelEvent-deltaX) from the W3C.
*/
@DomName('WheelEvent.deltaX')
- num get deltaX => -$dom_wheelDeltaX;
+ num get deltaX => -_wheelDeltaX;
/**
* The amount that is expected to scroll vertically, in units determined by
@@ -241,6 +241,6 @@
* * [WheelEvent.deltaY](http://dev.w3.org/2006/webapi/DOM-Level-3-Events/html/DOM3-Events.html#events-WheelEvent-deltaY) from the W3C.
*/
@DomName('WheelEvent.deltaY')
- num get deltaY => -$dom_wheelDeltaY;
+ num get deltaY => -_wheelDeltaY;
$endif
}
diff --git a/tools/dom/templates/html/impl/impl_Window.darttemplate b/tools/dom/templates/html/impl/impl_Window.darttemplate
index f60f7d495..9c8f8ce 100644
--- a/tools/dom/templates/html/impl/impl_Window.darttemplate
+++ b/tools/dom/templates/html/impl/impl_Window.darttemplate
@@ -152,7 +152,7 @@
return _requestAnimationFrame(callback);
}
- void cancelAnimationFrame(id) {
+ void cancelAnimationFrame(int id) {
_ensureRequestAnimationFrame();
_cancelAnimationFrame(id);
}
@@ -205,7 +205,7 @@
this, this, this);
@DomName('Window.console')
- Console get console => Console.safeConsole;
+ Console get console => Console._safeConsole;
/// Checks if _setImmediate is supported.
static bool get _supportsSetImmediate =>
diff --git a/tools/gyp/configurations_make.gypi b/tools/gyp/configurations_make.gypi
index abced4d..05a3bad 100644
--- a/tools/gyp/configurations_make.gypi
+++ b/tools/gyp/configurations_make.gypi
@@ -55,6 +55,7 @@
'-Wno-psabi', # suppresses va_list warning
'-fno-strict-overflow',
],
+ 'ldflags': ['-static'],
}],
['_toolset=="host"', {
'cflags': ['-m32', '-msse2'],
diff --git a/tools/testing/dart/test_runner.dart b/tools/testing/dart/test_runner.dart
index 4261cec..94c33bb 100644
--- a/tools/testing/dart/test_runner.dart
+++ b/tools/testing/dart/test_runner.dart
@@ -846,7 +846,7 @@
} else if (fields[ERROR_LEVEL] == 'WARNING') {
// We only care about testing Static type warnings
// ignore all others
- if (fields[ERROR_TYPE] == 'STATIC_TYPE') {
+ if (fields[ERROR_TYPE] == 'STATIC_TYPE' || fields[ERROR_TYPE] == 'STATIC_TYPE_WARNING') {
staticWarnings.add(fields[FORMATTED_ERROR]);
}
}
@@ -970,6 +970,20 @@
}
}
+
+/** Modifies the --timeout=XX parameter passed to run_selenium.py */
+List<String> _modifySeleniumTimeout(List<String> arguments, int timeout) {
+ return arguments.map((argument) {
+ if (argument.startsWith('--timeout=')) {
+ return "--timeout=$timeout";
+ } else {
+ return argument;
+ }
+ }).toList();
+ return;
+}
+
+
/**
* A RunningProcess actually runs a test, getting the command lines from
* its [TestCase], starting the test process (and first, a compilation
@@ -1011,8 +1025,10 @@
_commandComplete(0);
} else {
var processOptions = _createProcessOptions();
+ var commandArguments = _modifySeleniumTimeout(command.arguments,
+ testCase.timeout);
Future processFuture = io.Process.start(command.executable,
- command.arguments,
+ commandArguments,
processOptions);
processFuture.then((io.Process process) {
// Close stdin so that tests that try to block on input will fail.
@@ -1177,7 +1193,8 @@
"environments for batch runner tests!");
}
- var line = _createArgumentsLine(testCase.batchTestArguments);
+ var line = _createArgumentsLine(testCase.batchTestArguments,
+ testCase.timeout);
_process.stdin.write(line);
_stdoutSubscription.resume();
_stderrSubscription.resume();
@@ -1185,7 +1202,8 @@
_stderrCompleter.future]).then((_) => _reportResult());
}
- String _createArgumentsLine(List<String> arguments) {
+ String _createArgumentsLine(List<String> arguments, int timeout) {
+ arguments = _modifySeleniumTimeout(arguments, timeout);
return arguments.join(' ').concat('\n');
}
diff --git a/tools/testing/dart/test_suite.dart b/tools/testing/dart/test_suite.dart
index bd0ddbd..329d087 100644
--- a/tools/testing/dart/test_suite.dart
+++ b/tools/testing/dart/test_suite.dart
@@ -998,7 +998,8 @@
args = [
dartDir.append('tools/testing/run_selenium.py').toNativePath(),
'--browser=$runtime',
- '--timeout=${configuration["timeout"]~/2}',
+ // NOTE: This value will be overridden by the test runner
+ '--timeout=${configuration['timeout']}',
'--out=$fullHtmlPath'];
if (runtime == 'dartium') {
args.add('--executable=$dartiumFilename');